Same table NHibernate mapping - c#

How can i go about defining a same table relation mapping (mappingbycode) using Nhibernate
for instance let's say I have a class:
public class Structure{
public int structureId;
public string structureName;
public Structure rootStructure;
}
that references the same class as rootStructure.
mapper.Class<Structure>(m =>
{
m.Lazy(true);
m.Id(u => u.structureId, map => { map.Generator(Generators.Identity); });
m.Property(c => c.structureName);
m.? // Same table mapping
}
;
Thanks

there is no special mapping for recursive mappings i am aware of. Just map it like you would map a collection of a different class. In your case this should work (untested though):
m.OneToOne(c => c.rootStructure, a => a.Lazy(LazyRelation.Proxy))
NHibernate will assume that the foreign key for this relation is stored on column rootStructure of the table associated to that class.

Related

Problem with master/detail tables and Entity Framework

I have a typical master/detail (User / Settings table) table schema (SQL Server) and setup Entity Framework using Fluent API to work with those tables.
I define this as an independent association, so the UserProfileSetting class doesn't include the UserId property, but I understand is correctly mapped in the configuration.
Well, my problem is that when one item of Settings is updated for a profile, at the database level that settings is updated for all users. Basically USER_ID is not considered.
The SQL query produced is this:
UPDATE [dbo].[T_USERPROFILE_SETTING]
SET [VALUE] = #0
WHERE ([KEY] = #1)
Any idea what could be wrong? I guess that if I finally add the UserId property to UserProfileSettings, that will fix the problem, but I wanted to try to fix this without it.
Current code below...
Code updating the data
var entry = profile.Settings.Where(s => s.Key == key).SingleOrDefault();
if (entry != null)
{
entry.Value = value;
} else {
var setting = /* Here create a new setting */
profile.Settings.Add(setting);
}
DataContext.SaveChanges();
Entities:
public partial class UserProfile
{
[Key]
public string UserId { get; set; }
public DateTimeOffset LastLogin { get; set; }
public ICollection<UserProfileSetting> Settings { get; set; }
}
public class UserProfileSetting
{
public UserProfileSetting() { }
public string Key { get; set; }
public string Value { get; set; }
}
Entity configuration:
public class UserProfileConfiguration : EntityTypeConfiguration<UserProfile>
{
public UserProfileConfiguration()
{
ToTable("T_USERPROFILE");
HasKey<string>(p => p.UserId);
Property(p => p.UserId)
.HasColumnName("USER_ID")
.HasMaxLength(50)
.IsUnicode()
.IsRequired();
Property(p => p.LastLogin)
.HasColumnName("LAST_LOGIN_AT")
.IsRequired();
HasMany<UserProfileSetting>(p => p.Settings)
.WithOptional()
.Map(m => m.MapKey("USER_ID"));
}
}
public class UserProfileSettingConfiguration : EntityTypeConfiguration<UserProfileSetting>
{
public UserProfileSettingConfiguration()
{
ToTable("T_USERPROFILE_SETTING");
HasKey(p => p.Key );
Property(p => p.Key)
.HasColumnName("KEY")
.HasMaxLength(50)
.IsUnicode()
.IsRequired();
Property(p => p.Value)
.HasColumnName("VALUE")
.IsUnicode()
.IsRequired();
}
}
From EF documentation...
When foreign key columns are not included in the model, the association information is managed as an independent object. Relationships are tracked through object references instead of foreign key properties. This type of association is called an independent association. The most common way to modify an independent association is to modify the navigation properties that are generated for each entity that participates in the association.
So, I was wrong. In my code, UserProfile should include UserProfileSetting either as a FK (Just the ID) or as an independent Object.
In the 1st case a UserId should be mapped into UserProfileSetting and the navigation property in UserProfile should be changed to...
HasMany<UserProfileSetting>(p => p.Settings)
.WithOptional()
.HasForeignKey(s => s.UserId);
In the 2nd case, (this is what is called an Independent Association) a new navigation property should be added into UserProfileSetting for UserProfile.
Entity framework maps to relational database and so it must stick with some of it concepts. The main thing here is, that each entity is mapped to a table containing all the records of that entity and it needs some data to distinguish the relation.
Therefore you need to add USER_ID to tell which record is for which user (to define the relation). In other words you need to have it in table and also in C# entity.
I don’t think it is possible in code first to not have the relation property on entity. On the other hand, you can create some extra DTO layer to hide it.

Should I map both sides of bidirectional relations in EF code first?

Assume I have the following entity classes:
public class Customer {
public int Id { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
public class Order {
public int Id { get; set; }
public virtual Customer Customer { get; set; }
}
How should those be mapped in Entity Framework 6 fluent code-first mapping? I want to be explicit about the mapping and not rely on automatic mapping conventions.
Option 1
Just map the local properties of both classes. That's how I would do it in Fluent NHibernate.
public class CustomerMap : EntityTypeConfiguration<Customer> {
public CustomerMap() {
HasMany(x => x.Orders);
}
}
public class OrderMap : EntityTypeConfiguration<Order> {
public OrderMap() {
HasRequired(x => x.Customer);
}
}
Option 2
Map both sides of the relationship in both classes.
public class CustomerMap : EntityTypeConfiguration<Customer> {
public CustomerMap() {
HasMany(x => x.Orders).WithRequired(x => x.Customer);
}
}
public class OrderMap : EntityTypeConfiguration<Order> {
public OrderMap() {
HasRequired(x => x.Customer).WithMany(x => x.Orders);
}
}
Option 3
Map both sides of the relation, but only in one of the classes. The code would be similar to option 2, just one of the two constructors would be empty.
Is there any difference between those options? If yes, please also explain why I should or shouldn't use a specific option.
I would go for option 3.
In option 1 you can forget to map the inverse end of an association. In this simple example it's clear that Order.Customer and Customer.Orders are two ends of the same association. When things get more complex, this isn't always obvious. Also, it is redundant code.
In option 2 you could have conflicting mappings. For instance when you have...
HasOptional(x => x.Customer).WithMany(x => x.Orders);
...in OrderMap, you will get a runtime exception telling you that both mappings don't match. And again, it is redundant code.
So option 3 is DRY and safe. The only issue is that it's a bit arbitrary where to configure the mappings. I tend to adhere to mapping children in their parent's mapping.
One more comment. You may want to add a primitive property CustomerId in Order. The mapping would look like:
public class CustomerMap : EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
HasMany(x => x.Orders).WithRequired(x => x.Customer)
.HasForeignKey(o => o.CustomerId);
}
}
Now you have full control over both ends of the association and the foreign key name to be used. Besides that, there are some advantages of these foreign key associations as opposed to independent associations (without a primitive foreign key property). For instance, the ability to establish an association without having to fetch the parent object from the database. You can just by set an Id value.

(Fluent) NHibernate table-per-hierarchy; Id is only unique along with discriminator

I have a legacy database mapping issue. The database is storing all of its lookup values (code/description) in one table, distinguished by a type code field. The tables referring to it do so with one column (the code, without the type code). The code table does not have a primary key constraint (!).
I have a class that looks like this:
public class Code
{
[StringLength(8)]
public virtual string CodeValue { get; set; }
[StringLength(2000)]
public virtual string Description { get; set; }
public virtual long? OrderBy { get; set; }
public virtual DateTime? StopDate { get; set; }
}
My initial mapping looked like this:
public class CodesMap : ClassMap<Code>
{
public CodesMap()
{
Table("CODES");
Id(x => x.CodeValue).Column("CODE_CODE").GeneratedBy.Assigned();
Map(x => x.Description).Column("DESCRIPTION");
Map(x => x.OrderBy).Column("ORDER_BY");
DiscriminateSubClassesOnColumn("TYPE_CODE", "INVALID")
.SqlType("VARCHAR2");
}
}
And then there are a bunch of sub-classes that differ only in their discriminator values.
Another mapping might reference this as:
...
References<FacilityType>(x => x.Type).Column("FACIL_TYPE_CODE").ReadOnly();
...
Now, this is all well and good, and everything works, since that reference knows the class, and therefore the discriminator value for the query, except...I only just hit the case where CODE_CODE is non-unique between two objects of different types (both subtypes of Code) in the same session. Oops.
CODE_CODE and TYPE_CODE are unique together, so the right thing ought to be to use them as a composite key. But then my References in the other class maps become impossible, because those tables only have a single column foreign key (obviously no FK constraint defined on table).
Short of adding a surrogate key on the code table, whatever shall I do?
In case, that we need to map look up values as readonly, solution would be surprisingly very easy. Instead of explicit inheritance, we will explicitly map each subclass. The discriminator will be moved to a WHERE clause:
public FacilityTypeMap()
{
Table("CODES");
// here we will use explicit runtime discriminator
// injected by NHibernate into each SELECT .. FROM clause for this type
Where(" TYPE_CODE = 'FACIL_TYPE' " )
Id(x => x.CodeValue).Column("CODE_CODE").GeneratedBy.Assigned();
Map(x => x.Description).Column("DESCRIPTION");
Map(x => x.OrderBy).Column("ORDER_BY");
// no more inheritance
// DiscriminateSubClassesOnColumn("TYPE_CODE", "INVALID")
// .SqlType("VARCHAR2");
}
This is very well working for SELECT. We just have to repeat that mapping for each Discriminator == each derived type.
see 5.1.3. class:
<class
name="ClassName" (1)
table="tableName" (2)
...
where="arbitrary sql where condition" (11)
(11) where (optional) specify an arbitrary SQL WHERE condition to be used when retrieving objects of this class
In case, we need to use this class also for insert, we have to do few more steps. Explicitly map column 'TYPE_CODE' as e.g. Discriminator, and set it in constructor to correct value (e.g. 'FACIL_TYPE'). It could be protected property mapped as .Not.Update()
string _discriminator = "FACIL_TYPE";
public virtual string Discriminator { get { return _discriminator; } protected set {} }
...
// mapping
Map(x => x.Discriminator, "TYPE_CODE").Not.Update()

Force Mapping of only logical Foreign Key in Code First

I am using Entity Framework and Code First to map to a legacy database (I know that if I have the database already built then I should the "Database First" approach, but some how, I fill better putting the annotations by hand than handling control over the designer), in which, there is a table that have a key that point to another table (it is actually a synonym to a table in another db) that works like a foreign key but it not actually defined in the table schema.
The question is: can I force this relation to exist in my POCO classes? can I map this using the Fluent API? is this possible at all?
As usual, thanks in advance!
Sure, you can manually define a foreign key and navigation properties either by fluent mapping or data annotations.
Let's say I have a Parent table with a field CatCode and a synonym CategoryEx that points to a table Category in a second database. Both have corresponding classes and DbSets in one context. The mappings (derived from EntityTypeConfiguration) could look like (the constructors):
public ParentMap()
{
this.HasKey(t => t.Id);
this.HasRequired(p => p.Category).WithMany().HasForeignKey(p => p.CatCode);
...
}
public CategoryMap()
{
this.HasKey(t => t.CatCode);
this.ToTable("CategoryEx");
...
}
where Parent looks like:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public string CatCode { get; set; }
...
public Category Category { get; set; }
}

Entity Framework + AutoMapper ( Entity to DTO and DTO to Entity )

I've got some problems using EF with AutoMapper. =/
for example :
I've got 2 related entities ( Customers and Orders )
and they're DTO classes :
class CustomerDTO
{
public string CustomerID {get;set;}
public string CustomerName {get;set;}
public IList< OrderDTO > Orders {get;set;}
}
class OrderDTO
{
public string OrderID {get;set;}
public string OrderDetails {get;set;}
public CustomerDTO Customers {get;set;}
}
//when mapping Entity to DTO the code works
Customers cust = getCustomer(id);
Mapper.CreateMap< Customers, CustomerDTO >();
Mapper.CreateMap< Orders, OrderDTO >();
CustomerDTO custDTO = Mapper.Map(cust);
//but when i try to map back from DTO to Entity it fails with AutoMapperMappingException.
Mapper.Reset();
Mapper.CreateMap< CustomerDTO , Customers >();
Mapper.CreateMap< OrderDTO , Orders >();
Customers customerModel = Mapper.Map< CustomerDTO ,Customers >(custDTO); // exception is thrown here
Am I doing something wrong?
Thanks in Advance !
The problem I had was related to updates to EntityCollection references. AutoMapper creates a new instance of the relation when mapping from the DTO to the Entity, and that doesn't please the EF.
What solved my problem was configuring AutoMapper to use the destination value for my EntityCollection properties. In your case:
Mapper.CreateMap< CustomerDTO , Customers >().ForMember(c => c.Orders, o => o.UseDestinationValue());
That way AM will not create a new EntityCollection instance, and will use that wich came with the original Customer entity.
I'm still working for a way to automate this, but for now it solves my problem.
Try mapping to an existing object:
entity = Mapper.Map<MyDTO, NyEntity>(dto, entity);
And keep the Ignore()'s in place.
http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1
Your problem is because Automapper loses the EntityKey associated with the record. As the EntityFramework does not by default handle POCO's (Plain Old CLR Object)
Jay Zimmerman has a good example here of how to handle this from is. gd /4NIcj
Also from Jaroslaw Kowalski (part of the EF team I believe ) has this example for using POCO's within EF, which may translate well to use with Automapper (I've not yet had a chance to try it) : http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx
I'm not sure what your problem is, but - when i wanted to use LINQToEntities (switched to NHibernate),
i managed to use automapper with success.
Take a look at code:
public class SimpleMapper<TFrom, TTo>
{
public static TTo Map(TFrom fromModel)
{
Mapper.CreateMap<TFrom, TTo>();
return Mapper.Map<TFrom, TTo>(fromModel);
}
public static IList<TTo> MapList(IList<TFrom> fromModel)
{
Mapper.CreateMap<TFrom, TTo>();
return Mapper.Map<IList<TFrom>, IList<TTo>>(fromModel);
}
}
public class RepositoryBase<TModel, TLINQModel>
{
public IList<TModel> Map<TCustom>(IList<TCustom> model)
{
return SimpleMapper<TCustom, TModel>.MapList(model);
}
public TModel Map(TLINQModel model)
{
return SimpleMapper<TLINQModel, TModel>.Map(model);
}
public TLINQModel Map(TModel model)
{
return SimpleMapper<TModel, TLINQModel>.Map(model);
}
public IList<TModel> Map(IList<TLINQModel> model)
{
return SimpleMapper<TLINQModel, TModel>.MapList(model);
}
public IList<TLINQModel> Map(IList<TModel> model)
{
return SimpleMapper<TModel, TLINQModel>.MapList(model);
}
}
It's quite cryptic, always recreates mappings, but it worked. I hope it helps somehow. :)
Now, with new version of AutoMapper, the recommended way is using Queryable-Extensions:
When using an ORM such as NHibernate or Entity Framework with
AutoMapper's standard Mapper.Map functions, you may notice that the
ORM will query all the fields of all the objects within a graph when
AutoMapper is attempting to map the results to a destination type.
If your ORM exposes IQueryables, you can use AutoMapper's
QueryableExtensions helper methods to address this key pain.
The .ProjectTo() will tell AutoMapper's mapping engine
to emit a select clause to the IQueryable that will inform entity
framework that it only needs to query the Name column of the Item
table, same as if you manually projected your IQueryable to an
OrderLineDTO with a Select clause.
Create a mapping:
Mapper.CreateMap<Customer, CustomerDto>();
And project query to dto:
var customerDto =
session.Query<Customer>().Where(customer => customer.Id == id)
.Project().To<CustomerDto>()
.Single();
AutoMapper is very expressive when it comes to mapping error. read the exception message carefully.
another important thing is to remember to call Mapper.AssertConfigurationIsValid(); after creating the mappings. it gives an error if the mapping is wrong, thus preventing an exception later in the application runtime.
You should ignore mapping of some entity properties like so:
Mapper.CreateMap<CustomerDto, Customer>()
.ForMember(dest => dest.EntityKey, opt => opt.Ignore())
.ForMember(dest => dest.Licenses, opt => opt.Ignore())
.ForMember(dest => dest.AccessCodes, opt => opt.Ignore());
If you examine the message from the exception thrown by Automapper, you should see the entity properties that cannot be mapped and ignore them as above.
As you can read here you need to do the following
You can update entities with AutoMapper. Here's how: pass both the DTO and the entity object to AutoMapper's Map method. That's what this code does:
custExisting = Mapper.Map(Of CustomerDTO, Customer)(custDTO, custExisting)
Also beware of mapping issues like the one described here
These tips worked for me.

Categories

Resources