我已经被提交并已经开始学习Fluent NHibernate(没有以前的NHibernate经验).在我的项目中,我正在编程接口以减少耦合等.这意味着几乎所有"一切"都指的是接口而不是具体类型(IMessage而不是Message).这背后的想法是通过能够模拟依赖关系来帮助使其更易于测试.
然而,(流利的)当我尝试映射到接口而不是具体类时,NHibernate并不喜欢它.问题很简单 - 根据Fluent Wiki,定义我的类的ID字段是明智的
int Id { get; private set; }
Run Code Online (Sandbox Code Playgroud)
获取典型的自动生成的主键.但是,这只适用于具体的类 - 我不能在接口上指定访问级别,同一行必须是这样
int Id { get; set; }
Run Code Online (Sandbox Code Playgroud)
并且我认为否定在具体类中使setter私有(想法是只有NHibernate应该将ID设置为由DB分配).
就目前而言,我想我只会公开制定者并试图避免写入它的诱惑..但是有没有人知道什么是"正确的",最佳实践方式来创建一个正确的主键只有NHibernate可以写入的字段,而仍然只编程到接口?
更新
根据我从mookid和James Gregory的两个答案之后的理解,我可能走错了路 - 我不应该有理由让每个实体拥有一个接口,就像我现在一样.这一切都很好.我想我的问题就变成了 - 是否没有理由对任何实体的接口进行100%编程?如果甚至有一种情况可以证明这是合理的,那么可以用(流利的)NHibernate做到这一点吗?
我问,因为我不知道,不要批评.谢谢你的回复.:)
我收到此异常(底部的完全例外):
NHibernate.PropertyValueException was unhandled by user code
Message="not-null property references a null or transient
valueClearwave.Models.Encounters.Insurance.Patient"
Source="NHibernate"
EntityName="Clearwave.Models.Encounters.Insurance"
PropertyName="Patient"
Run Code Online (Sandbox Code Playgroud)
我已经做了很多谷歌搜索,似乎这个错误最常见的原因是当一个关联是双向的但只有一半被设置.如:Insurance.Patient =患者被叫,但Patient.Insurances.Add(保险)不是.事实上,我确实有这样的场景,但我在调用Save之前检查了对象,并且Insurance.Patient和Patient.Insurances [0]都是正确的对象.
此异常似乎引用的另一种可能性是瞬态值.在我的情况下,每个对象都是暂时的,所以我怀疑问题的根源在这里.但是,现在一切都需要暂时,因为还没有保存.我希望NHibernate能够持久存在而不是抱怨它们不会被持久存在.
以下是我映射的一些片段(流利):
public PatientMap()
{
WithTable("tPatient");
Id(x => x.Id, "uid_Patient").GeneratedBy.GuidComb
().Access.AsReadOnlyPropertyThroughCamelCaseField();
HasMany(x => x.Insurances).WithKeyColumn("uid_Patient")
.Cascade.All()
.Inverse();
...
}
public InsuranceMap()
{
WithTable("tPatientInsuranceInfo");
Id(x => x.Id,
"uid_PatientInsuranceInfo").GeneratedBy.GuidComb
().Access.AsReadOnlyPropertyThroughCamelCaseField();
References(x => x.Patient, "uid_Patient").Not.Nullable
().Cascade.All();
...
}
Run Code Online (Sandbox Code Playgroud)
那么,可能是什么问题呢?
NHibernate.PropertyValueException was unhandled by user code
Message="not-null property references a null or transient
valueClearwave.Models.Encounters.Insurance.Patient"
Source="NHibernate"
EntityName="Clearwave.Models.Encounters.Insurance"
PropertyName="Patient"
StackTrace:
at NHibernate.Engine.Nullability.CheckNullability(Object[]
values, IEntityPersister …Run Code Online (Sandbox Code Playgroud) c# nhibernate exception nhibernate-mapping fluent-nhibernate
我需要通过编写一个实现的新mapper类来为NHibernate创建一个自定义类型.虽然覆盖大多数方法和属性相对简单,但我理解如何正确处理以下成员会遇到一些困难:IUserType
object Assemble(object cached, object owner);object DeepCopy(object value);object Disassemble(object value);object Replace(object original, object target, object owner);我不明白他们的目的是什么; 更重要的是,如何正确实施它们.我见过的大多数示例都只返回原始输入参数.
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
Run Code Online (Sandbox Code Playgroud)
如何在实际情况或更复杂的情况下正确实现这些方法?
我用过这个如何使用流畅的NHibernate将枚举映射为int值?在过去映射,但我最近升级到NHibernate 3,这似乎不再起作用了.我在我的EnumConvention课程中放了断点,但它们没有被击中.命中数据库的查询将枚举作为字符串,这是默认配置.
这如何与NHibernate 3一起使用?
更新
以下是生成的映射文件的一部分:
<property name="ComponentType" type="FluentNHibernate.Mapping.GenericEnumMapper`1[[...ComponentType, ..., Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], FluentNHibernate, Version=1.1.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880">
<column name="ComponentTypeId" />
</property>
Run Code Online (Sandbox Code Playgroud)
如果为枚举指定了GenericEnumMapper何时使用它似乎是正确的IUserTypeConvention.
这是我的惯例:
public class EnumConvention : IUserTypeConvention
{
public void Accept( IAcceptanceCriteria<IPropertyInspector> criteria )
{
criteria.Expect( e => e.Property.PropertyType.IsEnum );
}
public void Apply( IPropertyInstance instance )
{
instance.CustomType( instance.Property.PropertyType );
}
}
Run Code Online (Sandbox Code Playgroud) 通过代码使用NHibernate 3.2映射(不是fluent-nhibernate),我试图将Enum字段映射到字符串列而不是默认的int表示.我无法获得正确的语法.
例如:
public class Account {
public enum StateType { Pending, Active, Cancelled, Suspended }
...
public virtual StateType State { get; set; }
...
}Run Code Online (Sandbox Code Playgroud)
在XML映射中,您可以使用NHibernate.Type.EnumStringType(请参阅此链接),但如何通过代码进行映射?
NHibernate.Mapping.ByCode.ModelMapper mapper = new NHibernate.Mapping.ByCode.ModelMapper();
mapper.Class<Account>(map => {
map.Id(x => x.Id, attr => {
attr.Column("id");
attr.Generator(NHibernate.Mapping.ByCode.Generators.Identity);
});
// Default 'int' mapping
//map.Property(x => x.State);
// Cannot implicitly convert type 'StateType' to 'NHibernate.Type.EnumStringType'
//map.Property<NHibernate.Type.EnumStringType<Account.StateType>>(x => x.State);
Run Code Online (Sandbox Code Playgroud)
更新:
使用此映射,我设法将其作为字符串保存到数据库中,但是现在从DB加载到对象模型时会出现异常.
map.Property(x => x.State, attr => { attr.Type(NHibernateUtil.String); });
这是我在尝试加载对象时遇到的异常:
Invalid Cast …Run Code Online (Sandbox Code Playgroud) 我有一个父对象,它与一个ISet子对象有一对多的关系.子对象具有唯一约束(PageNum以及ContentID- 父对象的外键).
<set name="Pages" inverse="true" cascade="all-delete-orphan" access="field.camelcase-underscore">
<key column="ContentId" />
<one-to-many class="DeveloperFusion.Domain.Entities.ContentPage, DeveloperFusion.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</set>
Run Code Online (Sandbox Code Playgroud)
我打的问题是,如果我删除ContentPage从父集合元素,然后添加与同一事务中相同的唯一密钥一个新的...你得到一个违反唯一约束,因为NHibernate的尝试执行插入之前的删除.
有没有办法强制NHibernate首先执行删除?
所以我正在尝试使用NHibernate更新MS SQL 2005数据库中的对象.请记住,这是许多实时系统中使用的遗留数据库,我无法删除触发器.
当我的数据提供程序尝试.SaveOrUpdate()行时,我得到两个返回(一个用于实际更新,一个用于执行触发器)
原始回报看起来像这样:
(1排受影响)
(1排受影响)
然后NHibernate抛出一个这样的异常:"意外的行数:2;预期:1"
我基本上在会话中看起来相当于"SET NOCOUNT ON".
有任何想法吗?
我有个问题.想象一下这个数据模型:
[Person] table has: PersonId, Name1
[Tag] table has: TagId, TagDescription
[PersonTag] has: PersonId, TagId, IsActive
Run Code Online (Sandbox Code Playgroud)
由于[PersonTag]不仅仅是一个简单的多对多连接表,我在nHibernate中创建了所有三个实体(就像它们在数据模型中一样).PersonTag因此,需要一个复合ID,我已经映射到这样的类:
<composite-id name="PersonTagKey" class="PersonTagKey">
<key-property name="PersonId"></key-property>
<key-property name="TagId"></key-property>
</composite-id>
Run Code Online (Sandbox Code Playgroud)
我想遍历对象图,并能够从检索到的对象中查看Person和对象.所以,我在对象上有属性来做,像这样映射:TagPersonTagPersonTag
<many-to-one name="Person" column="PersonId" lazy="proxy" cascade="none" class="Person"/>
<many-to-one name="Tag" column="TagId" lazy="proxy" cascade="none" class="Tag"/>
Run Code Online (Sandbox Code Playgroud)
当我尝试创建一个PersonTag对象并保存它时,我得到一个"此SqlParameterCollection的无效索引n,其中Count = n"错误.我知道这是因为我已经映射PersonId和TagId性能两次,一次为复合-ID,并曾经为许多一对一的关系.如果我不映射多对一对象,那么一切正常.
有没有办法让我能够在同一个nHibernate实体中建模的同一列中拥有复合ID和多对一关系?
在我的系统中,我有两个实体 - ShoppingCart和ShoppingCartItem.相当通用的用例.但是,当我保存我的ShoppingCart时,没有任何项目保存到数据库中.
在我的对象中,我创建了一个新的ShoppingCart对象.
ShoppingCart cart = CreateOrGetCart();
Run Code Online (Sandbox Code Playgroud)
然后,我将从数据库中获得的现有产品添加到开头.
cart.AddItem(product);
Run Code Online (Sandbox Code Playgroud)
这只是将项添加到IList的简单包装器.
public virtual void AddItem(Product product)
{
Items.Add(new ShoppingCartItem { Quantity = 1, Product = product });
}
Run Code Online (Sandbox Code Playgroud)
然后我在Repository上调用SaveOrUpdate
Repository.SaveOrUpdate(cart);
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
public T SaveOrUpdate(T entity)
{
Session.SaveOrUpdate(entity);
return entity;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用Fluent NHibernate进行映射:
public ShoppingCartItemMap()
{
WithTable("ShoppingCartItems");
Id(x => x.ID, "ShoppingCartItemId");
Map(x => x.Quantity);
References(x => x.Cart, "ShoppingCartId").Cascade.SaveUpdate();
References(x => x.Product, "ProductId");
}
public ShoppingCartMap()
{
WithTable("ShoppingCarts");
Id(x => x.ID, "ShoppingCartId");
Map(x => x.Created);
Map(x => x.Username);
HasMany<ShoppingCartItem>(x => x.Items)
.IsInverse().Cascade.SaveUpdate() …Run Code Online (Sandbox Code Playgroud) 我的数据库中有以下表格:
Announcements:
- AnnouncementID (PK)
- Title
AnouncementsRead (composite PK on AnnouncementID and UserID):
- AnnouncementID (PK)
- UserID (PK)
- DateRead
Users:
- UserID (PK)
- UserName
Run Code Online (Sandbox Code Playgroud)
通常我会使用多对多关系映射"AnnouncementsRead",但此表还有一个额外的"DateRead"字段.
到目前为止,我已经定义了以下实体:
public class Announcement
{
public virtual int AnnouncementID { get; set; }
public virtual string Title { get; set; }
public virtual IList<AnnouncementRead> AnnouncementsRead { get; private set; }
public Announcement()
{
AnnouncementsRead = new List<AnnouncementRead>();
}
}
public class AnnouncementRead
{
public virtual Announcement Announcement { get; set; } …Run Code Online (Sandbox Code Playgroud) nhibernate composite-key nhibernate-mapping fluent-nhibernate composite-id