问题
Here is the situation:
- WebApi v1
- Breeze 1.4.7
- EF 5.0/NHibernate 3.3.1
What We want: A many to many exposed as a many to one. A client can have multiple countries and a country can have multiple clients. A ClientCountry entity has been created for that purpose.
My mapping looks like this:
Entity Framework:
modelBuilder.Entity<Client>().HasKey(p => p.Id).Property(p=>p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Client>().Property(p => p.Abbreviation);
modelBuilder.Entity<Client>().Property(p => p.ClientSinceDate).IsRequired();
modelBuilder.Entity<Client>().Property(p => p.ClientUntilDate);
modelBuilder.Entity<Client>().Property(p => p.Name).IsRequired();
modelBuilder.Entity<Client>().Property(p => p.Website);
modelBuilder.Entity<Client>().HasMany(p => p.Contacts).WithRequired(p => p.Client).WillCascadeOnDelete(true);
modelBuilder.Entity<Client>().HasMany(p => p.ClientCountries).WithRequired(p => p.Client).WillCascadeOnDelete(true);
modelBuilder.Entity<Contact>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Contact>().Property(p => p.Username);
modelBuilder.Entity<Contact>().HasRequired(p => p.Client);
modelBuilder.Entity<Country>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Country>().Property(p => p.ValidFrom);
modelBuilder.Entity<Country>().Property(p => p.ValidTo);
modelBuilder.Entity<Country>().Property(p => p.Code);
modelBuilder.Entity<Country>().Property(p => p.DefaultLabel);
modelBuilder.Entity<Country>().Property(p => p.Description);
modelBuilder.Entity<Country>().Property(p => p.DisplayOrder);
modelBuilder.Entity<ClientCountry>().HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ClientCountry>().Property(p => p.ValidFrom);
modelBuilder.Entity<ClientCountry>().Property(p => p.ValidTo);
modelBuilder.Entity<ClientCountry>().HasRequired(p => p.Client);
modelBuilder.Entity<ClientCountry>().HasRequired(p => p.Country);
NHibernate:
public class BaseMapping<T> : ClassMapping<T> where T : BaseEntity
{
public BaseMapping()
{
this.Lazy(true);
Id(x => x.Id, map => { map.Generator(Generators.GuidComb); });
}
}
public class ClientMap : BaseMapping<Client>
{
public ClientMap()
{
this.Property(x => x.Name);
this.Property(x => x.Abbreviation);
this.Property(x => x.ClientSinceDate, map => map.NotNullable(true));
this.Property(x => x.ClientUntilDate);
this.Property(x => x.City);
this.Property(x => x.Website);
this.Bag<Department>(x => x.Departments, colmap =>
{
colmap.Key(x => x.Column("ClientId"));
colmap.Inverse(true);
colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
}, map =>
{
map.OneToMany();
});
this.Bag<ClientCountry>(x => x.ClientCountries, colmap =>
{
colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
colmap.Key(p => p.Column("ClientId"));
colmap.Inverse(true);
}, map =>
{
map.OneToMany();
});
this.Bag<Contact>(x => x.Contacts, colmap =>
{
colmap.Key(x => x.Column("ClientId"));
colmap.Cascade(Cascade.All | Cascade.DeleteOrphans);
}, map =>
{
map.OneToMany();
});
}
}
public class CountryMap : BusinessRefEntityMapping<Country>
{
public CountryMap()
{
Bag<ClientCountry>(x => x.ClientCountries, colmap =>
{
colmap.Cascade(Cascade.All);
colmap.Key(p => p.Column("CountryId"));
}, map =>
{
map.OneToMany();
});
}
}
public class ClientCountryMap : BaseMapping<ClientCountry>
{
public ClientCountryMap()
{
Property(x => x.ValidFrom);
Property(x => x.ValidTo);
Property(x => x.ClientId, map =>
{
map.Column("ClientId");
map.Insert(false);
map.Update(false);
map.NotNullable(true);
});
Property(x => x.CountryId, map =>
{
map.Column("CountryId");
map.Insert(false);
map.Update(false);
map.NotNullable(true);
});
ManyToOne<Client>(x => x.Client, map =>
{
map.Column("ClientId");
map.Cascade(Cascade.All);
map.Insert(true);
map.Update(true);
map.NotNullable(true);
});
ManyToOne<Country>(x => x.Country, map =>
{
map.Column("CountryId");
map.Cascade(Cascade.All);
map.Insert(true);
map.Update(true);
map.NotNullable(true);
});
}
}
The js code:
$scope.create = function (index) {
var c = $scope.clients[index];
var newClientCountry = breezeService.manager.createEntity('ClientCountry', {
ValidFrom: Date(2013, 01, 01),
ValidTo: Date(2015, 01, 01),
Client: c,
Country: country,
});
breezeService.manager.saveChanges()
.then(function (data) {
$log.info('client created');
})
.fail(function (dat) {
$log.error('save client failed:' + data)
})
}
The issue: With NHibernate, saving a clientcountry results in this error message :"not-null property references a null or transient value CdT.EAI.DAL.ClientCountry.Country". With EF, all works as expected.
Is there something wrong with my code?
回答1:
So, since there is no feedback yet, here's what we did to make it (more or less) work:
First, to be able to save a new ClientCountry(many to many with exposed junction table), we must do this:
public class ClientCountryMap : BaseMapping<ClientCountry> { public ClientCountryMap() { Property(x => x.ValidFrom); Property(x => x.ValidTo); Property(x => x.ClientId, map => { map.Column("ClientId"); map.Insert(true); map.Update(true); map.NotNullable(true); }); Property(x => x.CountryId, map => { map.Column("CountryId"); map.Insert(true); map.Update(true); map.NotNullable(true); }); ManyToOne<Client>(x => x.Client, map => { map.Column("ClientId"); map.Cascade(Cascade.All); map.Insert(false); map.Update(false); map.NotNullable(true); }); ManyToOne<Country>(x => x.Country, map => { map.Column("CountryId"); map.Cascade(Cascade.All); map.Insert(false); map.Update(false); map.NotNullable(true); }); } }
The difference here is that the insert/update are inverted.
Insert(true)
andUpdate(true)
must be set on the foreign key mapping and not the association. It differs from the breeze doc on that point.The second is that
Inverse(true)
must be set on each collection association or all your collections will be deleted when updating the parent entity.
With that,changes, it seems to work as expected.
ps: It is fixed in the latest version (>1.4.8). The comments above don't apply anymore.
来源:https://stackoverflow.com/questions/20684118/breeze-differences-between-entity-framework-and-nhibernate-with-many-to-many