Conditionally map two columns to one field with Fluent NHibernate - nhibernate

I have an NHibernate entity called Owner that has a SSN column and a TaxID column in the database, and I would like to conditionally map one of those two values to a more generic property on the Owner entity based on the value of a different property, StructureType. So, if the StructureType is "I", I want to map the SSN value to the generic property, and if its "C" I want to map the TaxID value to the generic property. Is this possible using Fluent NHibernate (or even regular NHibernate)? The Owner entity is a read-only entity, nothing will be written back to the database.

I was able to solve this using a Formula in Fluent NHibernate:
Map(x => x.Identification)
.Formula("CASE WHEN StructureType = 'I' THEN SSN ELSE TaxID END");
(In my original post I said it was between 'I' and 'C' but is in fact just between 'I' and every other type)

Why don't you add a readonly property?
public string Identification
{
get
{
string identification = string.Empty;
if (StructureType.Equals("I"))
identification = SSN;
else if (StructureType.Equals("C"))
identification = TaxID;
return identification;
}
}

Related

Laravel with() method, pass another column than the primary

I am using Eloquent to pull users out of my database, and i want to "join" the postal code from my users table with the postal code from my cities table, to retrieve the city name.
Heres a simplified version of my tables:
users =>
id
username
password
postal_code
cities =>
postal_code
city_name
In my User model i have a method called city() that declares the relationship with my cities table:
public function city() {
return $this->hasOne('cities', 'postal_code');
}
The problem now is when i try to do User::with('city')->find($user_id), the value being passed to the method is the primary key, the id, instead of the postal_code.
So my query ends up being (this is for the user with id 1):
select * from `cities` where `cities`.`postal_code` in ('1')
Is there someway to specify that i want to pass the postal_code instead?
There are a few things going on here. This is actually a belongs to relationship because the user holds the value that relates it to the city. The relationship would be better defined like this.
public function city()
{
return $this->belongsTo('City', 'postal_code');
}
The user only belongs to one city but the city has many users. In the City model you would have.
public function users()
{
return $this->hasMany('User', 'postal_code');
}
Now you will still have problems here because Laravel expects the relationships to use the primary key of the model. In order to get this working you will need to make the postal code the primary key for the City model.
class City extends Eloquent {
protected $primaryKey = 'postal_code';
}
This will effect every other place that you use a primary key with the City model but I think that should be OK given your current structure.
$city = City::find($postal_code);
I hate to throw a wrench into your plan here but in many places a city will have many postal codes. :)
Since the Relation class uses parent->getKey() (parent is User on your case) this will result in '1'.
I don't think changing the key for User to postal_code is good option ;)
So my guess is to give the users table a 'city_id' column and the cities an 'id' column, so things can work as designed.
An other would be not to return a relation, but something like.. return City::wherePostalCode($this->postal_code)->first();

enum as string and number in the database

i have a table
table Foo
(
id,
FooType,
FooTypeName,
)
FooType is an enum with fixed values hence i want to map it to
public virtual FooType FooType { get; set; }
How can i serialize the property in both columns but use only one to read and query?
Which mapping (xml, Mapping by Code, FluentMapping) doesn't matter
You could create FooTypeName as a string property projecting the value of FooType, and map it as readonly.
Alternatively, if you don't need FooTypeName at all, just ignore it in your model and keep it updated with a trigger.
Or, if you feel like coding a lot, create a user type that maps FooType to the two columns.

NHibernate wrongly comparing to null when deleting a component

I currently have an issue when updating a component collection on an entity. It was originally mapped as a bag but that was causing all entries to be deleted and reinserted each time. Changing it to a set has fixed that problem but introduced a new one.
The component type is called Tracking it has a composite key of UserID and ItemID and two properties which are nullable dates. When one of these is created DateRead set to the current time, it is then replaced later with an entry with the new date on.
The underlying SQL NHibernate generates has a where clause which checks that all properties match.
The issue is, the other date DateAcknowledged is often null, and the generated SQL seems to have a syntax error, to do a null check its doing this: = NULL rather than: IS NULL, as shown:
DELETE FROM TrackingTable
WHERE ItemId = 'a68f6dea-1c00-42e2-bc40-9fcf01121bd8' /* #p0 */
AND UserId = 'c8aa41a4-e4c2-4347-ae6e-b48738a53b47' /* #p1 */
AND DateRead = '2012-01-26T12:56:46.00' /* #p2 */
AND DateAcknowledged = NULL /* #p3 */
The thing is, the two dates should not be needed at all to determine what to delete. Simply having the where check item ID and user ID would do.
Here is the mapping code where I define the set:
Set(x => x.Trackings,
mapper =>
{
mapper.Key(k => k.Column("ItemId"));
mapper.Table("Tracking");
mapper.Access(Accessor.NoSetter);
},
collectionMapping => collectionMapping.Component(TrackingMap.Mapping()));
And here is the mapping for the component:
public class TrackingMap
{
public static Action<IComponentElementMapper<Tracking>> Mapping()
{
return c =>
{
c.ManyToOne(x => x.User, a => { a.Column("UserId"); a.ForeignKey("UserId"); });
c.Property(x => x.DateRead);
c.Property(x => x.DateAcknowledged, a => a.NotNullable(false));
};
}
}
Is there a way to tell NHibernate to use the keys only on the where clause or for it to compare nulls in the correct way?
This is covered by section 7.2. Collections of dependent objects which notes that this is not supported:
Please note that a composite element mapping doesn't support null-able properties if you're using a <set>. NHibernate has to use each columns value to identify a record when deleting objects (there is no separate primary key column in the composite element table), which is not possible with null values. You have to either use only not-null properties in a composite-element or choose a <list>, <map>, <bag> or <idbag>.
Please see this answer for a good explanation of how to delete NHibernate entities using criteria. This should allow you to use only ItemId and UserId when determining the items to delete and safely ignore the date comparisons.

NHibernate Criteria, select by count of property

Sorry for the cryptic title..
Could you help me out, on how do a select, based on the count of a property, using Criteria?
I have an object (Pool) with a property (PoolItems), and i want to select all the Pools w. more than 5 PoolItems.
Try this:
DetachedCriteria dCriteria = DetachedCriteria.For<PoolItem>("pItem")
.SetProjection(Projections.Count("Id"))
.Add(Restrictions.EqProperty("pItem.PoolID", "pool.Id"));
IList<Post> posts = Session.CreateCriteria<Pool>("pool")
.Add(Subqueries.Gt(5, dCriteria)).List<Pool>();
Assuming the PoolItem table has a PoolID column as a foreign key of the Pool table.
The relationship is a one-to-many. If you do not have the PoolID property mapped in the PoolItem class and you just have the many-to-one object mapping named "Pool" then replace in the detached criteria the "pItem.PoolID" with "pItem.Pool.Id".

What's the best way to handle "type" tables with LINQ to SQL?

I have some tables that represent various types. They usually just consist of an ID (int), and a name. Ideally I would have this in an enum. Is there a way to map a table like this onto an enum?
EDIT: How would I handle it if there were extra fields other than an ID and Name?
If it's just an id and a name, I generally do this:
public enum FootScent : int
{
Unknown = 0,
Mild = 1,
Sweaty =2,
SteppedInSomething = 3
}
and then on the LINQ entity property:
[Column("foot_scent_id", DbType = "Int NOT NULL")]
public FootScent Scent { get; set; }
For lookup tables with columns other than "id" and "name" that are needed, I usually just make a normal LINQ entity for them, though depending on your implementation it would probably be worth caching these to minimize trips to the DB.