Fluent Nhibernate:将单个实体映射到接口需求

Fluent Nhibernate:将单个实体映射到接口需求,nhibernate,fluent-nhibernate,interface,nhibernate-mapping,persistence,Nhibernate,Fluent Nhibernate,Interface,Nhibernate Mapping,Persistence,下午好 在我开始解释之前,我已经看了其他类似的问题,但细微的差异(主要是设计目的)意味着这些答案中提供的解决方案不适用于我 我正试图创建一个“基本数据访问库”,用于未来的项目,这样我就不必花时间在多个项目中编写相同的逻辑。其目的是简单地导入这个库,并立即拥有从IBaseDao继承的能力,并且从一开始就立即拥有标准的“CRUD”能力 因为(在编写这个基本库时)我无法确切地知道我的业务对象是什么(客户、文件结构、Cat、Dog、Order等),所以我在我的基本库中定义了一个接口,所有业务对象在与这个

下午好

在我开始解释之前,我已经看了其他类似的问题,但细微的差异(主要是设计目的)意味着这些答案中提供的解决方案不适用于我

我正试图创建一个“基本数据访问库”,用于未来的项目,这样我就不必花时间在多个项目中编写相同的逻辑。其目的是简单地导入这个库,并立即拥有从IBaseDao继承的能力,并且从一开始就立即拥有标准的“CRUD”能力

因为(在编写这个基本库时)我无法确切地知道我的业务对象是什么(客户、文件结构、Cat、Dog、Order等),所以我在我的基本库中定义了一个接口,所有业务对象在与这个库一起使用之前都必须实现该接口。此类接口定义如下:

public interface IEntity
{
    /// Indicates weather this entity is used as test
    /// data or if it is a real-world entity.
    bool IsMockObject { get; set; }

    /// This is not intended for use in a 'real' application
    /// and is only used in testing.
    string ReadableName { get; set; }

    /// The unique identifier for this object.
    Guid Id { get; set; }
}
因此,现在在“真实”应用程序中,我打算使用类似于以下内容的内容:

public class Customer : IEntity
{
    public Customer()
    {

    }

    string name = "";
    public virtual String Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }

    private DateTime birthday = DateTime.Now;
    public virtual DateTime Birthday
    {
        get;
        set;
    }

    private List<Order> orders = new List<Order>();
    public virtual List<Order> Orders
    {
        get
        {
            return orders;
        }
        set
        {
            orders = value;
        }
    }

    #region IEntity Members

    private bool isMockObject;
    public virtual bool IsMockObject
    {
        get
        {
            return true;
        }
        set
        {
            isMockObject = value;
        }
    }

    private string readableName;
    public virtual string ReadableName
    {
        get
        {
            return readableName;
        }
        set
        {
            readableName = value;
        }
    }

    private Guid id;
    public virtual Guid Id
    {
        get
        {
            return id;
        }
        set
        {
            id = value;
        }
    }
    #endregion
}
公共类客户:IEntity
{
公众客户()
{
}
字符串名称=”;
公共虚拟字符串名
{
得到
{
返回名称;
}
设置
{
名称=值;
}
}
私人DateTime生日=DateTime.Now;
公共虚拟日期时间生日
{
得到;
设置
}
私有列表顺序=新列表();
公共虚拟列表命令
{
得到
{
退货订单;
}
设置
{
订单=价值;
}
}
#地区成员
私有布尔对象;
公共虚拟bool IsMockObject
{
得到
{
返回true;
}
设置
{
isMockObject=值;
}
}
私有字符串可读名;
公共虚拟字符串可读名
{
得到
{
返回readableName;
}
设置
{
readableName=值;
}
}
私有Guid id;
公共虚拟Guid Id
{
得到
{
返回id;
}
设置
{
id=值;
}
}
#端区
}
这就是问题所在。在我的单元测试期间,当我尝试保存一个“客户”时,我得到一个参数计数不匹配异常。我怀疑这个问题的原因是数据库中的Customer表不包含所有IEntity属性的列。但是,它确实包含一个Id列。到目前为止,我的CustomerMap如下所示:

public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {
        Table("Customer");

        // From IEntity
        Id(x => x.Id);

        Map(x => x.Name);
        Map(x => x.Birthday);

        // From IEntity
        Map(x => x.IsMockObject);

        // From IEntity
        Map(x => x.ReadableName);
        HasMany(x => x.Orders);
    }
}
公共类CustomerMap:ClassMap
{
公共客户映射()
{
表(“客户”);
//从理性
Id(x=>x.Id);
Map(x=>x.Name);
Map(x=>x.birth);
//从理性
映射(x=>x.IsMockObject);
//从理性
Map(x=>x.ReadableName);
有很多(x=>x个订单);
}
}
保存时,我实际希望NHibernate执行的操作是将
Customer
特有的所有属性以及
IEntity.Id
属性保存在Customer表中,然后将模拟对象的Id及其可读名称保存在名为(如果IsMockEntity为true)的单独表中

我发现类映射目前很难理解,因为我在NHibernate基础持久性方面做得很少。非常感谢您对相关资料的任何帮助或链接


谢谢您的时间。

我要做的第一件事是

  • 将列表设置为IList;NHibernate需要能够将自己的枚举类型注入对象,而不是C#的定义列表
  • 确保NHibernate能够读取和写入所有属性,即不要在映射中设置默认值。如果需要,可以在构造函数(或其他地方)中执行
  • _

    公共类客户
    {
    公众客户()
    {
    IsMockObject=true;
    订单=新列表();
    }
    公共虚拟Guid Id{get;set;}
    公共虚拟字符串名称{get;set;}
    公共虚拟日期时间生日{get;set;}
    //受保护:用户无法修改此项!
    公共虚拟bool IsMockObject{get;protected set;}
    公共虚拟字符串ReadableName{get;set;}
    //需要是IList,而不是常规列表。
    公共虚拟IList命令{get;set;}
    }
    
    _


    我认为你的类地图没有任何问题,但我会先改变这些东西,然后看看有什么问题。如果仍然不起作用,请务必通知我们抛出的新异常。

    我要做的第一件事是

  • 将列表设置为IList;NHibernate需要能够将自己的枚举类型注入对象,而不是C#的定义列表
  • 确保NHibernate能够读取和写入所有属性,即不要在映射中设置默认值。如果需要,可以在构造函数(或其他地方)中执行
  • _

    公共类客户
    {
    公众客户()
    {
    IsMockObject=true;
    订单=新列表();
    }
    公共虚拟Guid Id{get;set;}
    公共虚拟字符串名称{get;set;}
    公共虚拟日期时间生日{get;set;}
    //受保护:用户无法修改此项!
    公共虚拟bool IsMockObject{get;protected set;}
    公共虚拟字符串ReadableName{get;set;}
    //需要是IList,而不是常规列表。
    公共虚拟IList命令{get;set;}
    }
    
    _


    我认为你的类地图没有任何问题,但我会先改变这些东西,然后看看有什么问题。如果仍然不起作用,请务必通知我们抛出的新异常。

    好的,我已经修改了代码以反映您建议的更改,并且还做了一些“挖掘”来尝试解决此问题。我现在拥有以下数据库结构:

    标签
    public class Customer
    {
        public Customer()
        {
            IsMockObject = true;
            Orders = new List<Order>();
        }
    
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual DateTime Birthday { get; set; }  
    
        // Protected: the user can't modify this!
        public virtual bool IsMockObject { get; protected set; }
    
        public virtual string ReadableName { get; set; }
    
        // Needs to be an IList<T>, NOT a regular List<T>.
        public virtual IList<Order> Orders { get; set; }
    }
    
     public class CustomerMap : ClassMap<Customer>
    {
        public CustomerMap()
        {
            Table("Customer");
    
            Id(x => x.Id);
            Map(x => x.Name);
            Map(x => x.Birthday);
            Join("MockEntities", me =>
                {
                    Id<Guid>("Id");
                    me.Map(xx => xx.ReadableName);
                    me.Map(xx => xx.Id, "EntityId");
                });
            HasMany(x => x.Orders).Cascade.All().Not.LazyLoad();
    
        }
    }
    
    public class OrderMap : ClassMap<Order>
    {
        public OrderMap()
        {
            Table("Order");
            Id(x => x.Id);
            Map(x => x.Price);
            Map(x => x.CustomerId, "CustomerId");
            Join("MockEntities", me =>
                {
                    Id<Guid>("Id");
                    me.Map(xx => xx.ReadableName);
                    me.Map(xx => xx.Id, "EntityId");
                });
        }
    }
    
    at System.Data.SqlServerCe.SqlCeCommand.CompileQueryPlan()
    at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
    at System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
    at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
    at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session)
    at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Object obj, ISessionImplementor session)
    at NHibernate.Action.EntityInsertAction.Execute()
    at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
    at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
    at NHibernate.Engine.ActionQueue.ExecuteActions()
    at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
    at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
    at NHibernate.Impl.SessionImpl.Flush()
    at NHibernate.Transaction.AdoTransaction.Commit()
    at MySolution.DataAccess.ConnectionProviders.NHibernateConnection.Create[TEntity](TEntity objectToCreate) in MySolution.DataAccess\ConnectionProviders\NHibernateConnection.cs:line 154
    at MySolution.Testing.DataAccess.Connection.Testing_Connections.Function_NHibernateCreateNestedEntity()
    
    NHibernate: INSERT INTO Customer (Name, Birthday, Id) VALUES (@p0, @p1, @p2);@p0 = 'David', @p1 = 03/09/2010 07:28:22, @p2 = 68fb7dd7-5379-430f-aa59-9de6007b2d56
    NHibernate: INSERT INTO MockEntities (ReadableName, EntityId, Customer_id) VALUES (@p0, @p1, @p2);@p0 = 'Function_NHibernateCreateNestedEntity1', @p1 = 00000000-0000-0000-0000-000000000000, @p2 = 68fb7dd7-5379-430f-aa59-9de6007b2d56
    07:28:28,851 ERROR [TestRunnerThread] AbstractBatcher [(null)]- Could not execute command: INSERT INTO MockEntities (ReadableName, EntityId, Customer_id) VALUES (@p0, @p1, @p2)
    The column name is not valid. [ Node name (if any) = ,Column name = Customer_id ]
    
    public class CustomerMap : ClassMap<Customer>
    {
        public CustomerMap()
        {
            Table("Customer");
    
            Id(x => x.Id);
    
            ...
    
    @p2 = 68fb7dd7-5379-430f-aa59-9de6007b2d56
    
    @p2 = '68fb7dd7-5379-430f-aa59-9de6007b2d56'
    
    public class CustomerMap : ClassMap<Customer>
    {
        public CustomerMap()
        {
            Table("Customer");
    
            Id<Guid>(x => x.Id);
    
            ...
    
    public interface IEntityBase
    {
        int Id { get; set; }
        DateTime? Created { get; set; }
    }
    
    public abstract class EntityBase : IEntityBase
    {
        public int Id { get; set; }
        public DateTime? Created { get; set ;}
    }
    
    public class Customer : EntityBase
    {
        public string Name { get; set; }
    }
    
    public class EntityBaseMap : ClassMap<EntityBase>
    {
        Id(x => x.Id);
        Map(x => x.Created);
    }
    
    public class CustomerMap : SubclassMap<Customer>
    {
        Map(x => x.Name);
    }