C# 是否有必要将实体类复制为视图模型以使用NHibernate?

C# 是否有必要将实体类复制为视图模型以使用NHibernate?,c#,nhibernate,fluent-nhibernate,asp.net-mvc-5,C#,Nhibernate,Fluent Nhibernate,Asp.net Mvc 5,我很难在MVC5中使用NHibernate。问题是NHibernate需要我的类的Id属性是私有的或受保护的,但是MVC模型绑定器无法在现有实体上设置Id,因此NHibernate将其视为新记录,并插入它而不是编辑它 public interface IEntity { int Id {get; } } public class User : IEntity { public virtual int Id {get; protected set;} public vir

我很难在MVC5中使用NHibernate。问题是NHibernate需要我的类的
Id
属性是私有的或受保护的,但是MVC模型绑定器无法在现有实体上设置Id,因此NHibernate将其视为新记录,并插入它而不是编辑它

public interface IEntity
{
    int Id {get; }
}

public class User : IEntity
{
    public virtual int Id {get; protected set;}
    public virtual string Email {get; set;}
    public virtual DateTime? LastLogin {get; set;}
}
这个很好用

public JsonResult SaveUser(User user)
{
    var userModel = new UserModel();
    if(userModel.SaveUser(user)) return Json(new {success = true});
    return Json(new {success = false});
}
这会失败,因为
Id
有一个受保护的集,这是NHibernate实体所必需的。因此,由于MVC模型绑定器无法设置
Id
,NHibernate将其视为一个新实体

public JsonResult EditUser(User user)
{
    var userModel = new UserModel();
    userModel.EditUser(user);
}
所以看起来我基本上需要将实体类复制为视图模型,但这看起来非常乏味(更不用说反干燥)。这两个类之间的唯一区别是视图模型类具有可公开设置的
Id
。通过使用,我可以稍微减少tedius,但是看起来我仍然需要将我的类复制为视图模型。它确实有一个从
dynamic
映射的功能,但这仍然不允许我为现有实体正确设置
Id


那么,我是不是遗漏了什么?有没有一种方法可以做到这一点,而不必创建两个几乎相同的类?

除非您在模型或视图模型中做一些有趣的事情,或者使用延迟加载,否则您不一定需要创建视图模型。我总是使用
NHibernate
models类,如果我需要一些特殊的模型,而不是精确的模型,那么我会创建单独的视图模型。例如,
登录
是使用视图模型执行的,因为密码有一些晶体学和安全选项。除此之外,我使用默认ASP.Net MVC模型绑定器的帮助,我的编辑功能通常如下所示-

意见-

@model ConsoleUser
<h2>Create</h2>

@Html.HiddenFor(x=>Model.Id)
......
@Html.EditorFor(x=>Model.UserName)
得到-

    /// <summary>
    /// Edits this instance.
    /// </summary>
    /// <returns></returns>
    [ValidateInput(false)]
    public virtual async Task<ActionResult> Edit(string id)
    {
        var item = (await _domainService.Get(x => x.Id == id)).FirstOrDefault();
        if (item.IsNotNull())
            return View(item);
        throw new CodedException("E.102.3");
    }
在save方法中,它看起来是这样的-

    public static void Save<T>(T entity, ISession _session = null, IList<Exception> errors = null) where T : IDomainEntity
    {
        if (_session == null)
        {
            using (var session = OpenEngineSession())
            using (var trans = session.BeginTransaction())
            {
                try
                {
                    session.SaveOrUpdate(entity);
                    trans.Commit();
                }
                catch (Exception e)
                {
                    errors = errors ?? new List<Exception>();
                    errors.Add(e);
                    trans.Rollback();
                }
            }
        }else
        {
            _session.SaveOrUpdate(entity);
        }
    }
publicstaticvoidsave(T entity,ISession\u session=null,IList errors=null),其中T:IDomainEntity
{
如果(_session==null)
{
使用(var session=OpenEngineSession())
使用(var trans=session.BeginTransaction())
{
尝试
{
会话。保存或更新(实体);
trans.Commit();
}
捕获(例外e)
{
错误=错误??新列表();
添加(e);
trans.Rollback();
}
}
}否则
{
_会话。保存或更新(实体);
}
}

仅此而已
NHibernate
有一个内置功能,即如果您使用通过NHibernate获取对象,它将保留一个引用,并将自动运行更新查询,而不是插入。

除非您在模型或视图模型中做了一些有趣的事情,或者使用延迟加载,否则您不一定需要创建视图模型。我总是使用
NHibernate
models类,如果我需要一些特殊的模型,而不是精确的模型,那么我会创建单独的视图模型。例如,
登录
是使用视图模型执行的,因为密码有一些晶体学和安全选项。除此之外,我使用默认ASP.Net MVC模型绑定器的帮助,我的编辑功能通常如下所示-

意见-

@model ConsoleUser
<h2>Create</h2>

@Html.HiddenFor(x=>Model.Id)
......
@Html.EditorFor(x=>Model.UserName)
得到-

    /// <summary>
    /// Edits this instance.
    /// </summary>
    /// <returns></returns>
    [ValidateInput(false)]
    public virtual async Task<ActionResult> Edit(string id)
    {
        var item = (await _domainService.Get(x => x.Id == id)).FirstOrDefault();
        if (item.IsNotNull())
            return View(item);
        throw new CodedException("E.102.3");
    }
在save方法中,它看起来是这样的-

    public static void Save<T>(T entity, ISession _session = null, IList<Exception> errors = null) where T : IDomainEntity
    {
        if (_session == null)
        {
            using (var session = OpenEngineSession())
            using (var trans = session.BeginTransaction())
            {
                try
                {
                    session.SaveOrUpdate(entity);
                    trans.Commit();
                }
                catch (Exception e)
                {
                    errors = errors ?? new List<Exception>();
                    errors.Add(e);
                    trans.Rollback();
                }
            }
        }else
        {
            _session.SaveOrUpdate(entity);
        }
    }
publicstaticvoidsave(T entity,ISession\u session=null,IList errors=null),其中T:IDomainEntity
{
如果(_session==null)
{
使用(var session=OpenEngineSession())
使用(var trans=session.BeginTransaction())
{
尝试
{
会话。保存或更新(实体);
trans.Commit();
}
捕获(例外e)
{
错误=错误??新列表();
添加(e);
trans.Rollback();
}
}
}否则
{
_会话。保存或更新(实体);
}
}

仅此而已
NHibernate
具有内置功能,从某种意义上说,如果您使用通过nhibernate获取对象,它将保留一个引用,并将自动运行更新查询而不是插入。

我建议使用MVC特定的视图模型,因为nhibernate模型通常实现动态代理,并且无法序列化为XML/JSON/等。它们可用于在视图中填充数据,但如果某些属性延迟加载数据,则会导致问题


视图模型可以接近数据模型类,但通常它们更特定于需要在屏幕上显示的内容。

我建议使用特定于MVC的视图模型,因为NHibernate模型通常实现动态代理,不能序列化为XML/JSON/等。它们可用于在视图中填充数据,但如果某些属性延迟加载数据,则会导致问题


视图模型可以接近数据模型类,但通常它们更特定于需要在屏幕上显示的内容。

NHibernate不需要Id是私有的或受保护的,您是从哪里得到这个想法的?假设它是一个自动递增的标识,将其设置为私有是一个很好的做法,但这不是必需的。使用视图模型是可选的,但从开发和应用程序安全的角度来看,这都是一个非常好的实践。例如,使用视图模型可以避免大规模分配攻击:

NHibernate不需要Id是私有的或受保护的,您是从哪里得到这个想法的?假设它是一个自动递增的标识,将其设置为私有是一个很好的做法,但这不是必需的。使用视图模型是可选的,但从开发和应用程序安全的角度来看,这都是一个非常好的实践。例如,使用view mod