【问题标题】:Entities are not persisted after creation实体在创建后不会持久化
【发布时间】:2019-10-20 02:36:38
【问题描述】:

免责声明:这是我第一个使用 NHibernate 的项目,我可能会遗漏一些“明显”的东西。

我的问题如下。我有一个创建订单的命令:

public void Handle(BuyOneProductCommand command)
{
    var product = _uow.Query<Product>().Single(p => p.Name == command.ProductName);
    var order = new Order(product, 1);
    _uow.SaveOrUpdate(order);
    _uow.Commit();
}

该命令接收一个新创建的UnitOfWork。但是在Commit() 之后,我的更改永远不会保存到数据库中,也不会抛出异常。有什么想法吗?

订购

public class Order : AggregateRoot
{
    public virtual Product Product { get; }
    public virtual int Quantity { get; }
    public virtual DateTime Date { get; }

    public Order(Product product, int quantity) : this()
    {
        Product = product;
        Quantity = quantity;
        Date = DateTime.Now;
        AddDomainEvent(new OrderCreatedEvent(this));
    }

    protected Order() { }
}

订单映射

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Id(x => x.Id);
        References(o => o.Product);
        Map(x => x.Quantity);
        Map(x => x.Date);
    }
}

工作单位

public sealed class UnitOfWork : IUnitOfWork
{
    private readonly ISession _session;
    private readonly ITransaction _transaction;
    private bool _isAlive = true;

    public UnitOfWork()
    {
        _session = SessionFactory.OpenSession();
        _transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted);
    }

    public void Commit()
    {
        if (!_isAlive)
            return;

        try
        {
            _transaction.Commit();
        }
        finally
        {
            _isAlive = false;
            _transaction.Dispose();
            _session.Dispose();
        }
    }

    public T Get<T>(long id) where T : class
    {
        return _session.Get<T>(id);
    }

    public void SaveOrUpdate<T>(T entity)
    {
        _session.SaveOrUpdate(entity);
    }

    public IQueryable<T> Query<T>()
    {
        return _session.Query<T>();
    }
}

会话工厂

public static class SessionFactory
{
    private static ISessionFactory _factory;

    public static void Init(string connectionString)
    {
        _factory = BuildSessionFactory(connectionString);
    }

    public static ISession OpenSession()
    {
        return _factory.OpenSession();
    }

    private static ISessionFactory BuildSessionFactory(string connectionString)
    {
        return Fluently.Configure()
            .Database(SQLiteConfiguration.Standard.ConnectionString(connectionString).ShowSql())
            .Mappings(m => m.FluentMappings
                .AddFromAssembly(Assembly.GetExecutingAssembly())
                .Conventions.Add(
                    ForeignKey.EndsWith("Id"),
                    ConventionBuilder.Property.When(criteria => criteria.Expect(x => x.Nullable, Is.Not.Set), x => x.Not.Nullable()))
                .Conventions.Add<OtherConventions>()
                .Conventions.Add<IncrementConvention>()
            )
            .ExposeConfiguration(x =>
            {
                x.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { new DomainEventsListener() };
                x.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { new DomainEventsListener() };
                x.EventListeners.PreDeleteEventListeners = new IPreDeleteEventListener[] { new DomainEventsListener() };
                x.EventListeners.PreCollectionUpdateEventListeners = new IPreCollectionUpdateEventListener[] { new DomainEventsListener() };
                x.EventListeners.PostCommitUpdateEventListeners = new IPostUpdateEventListener[] { new IntegrationEventsListener() };
                x.EventListeners.PostCommitInsertEventListeners = new IPostInsertEventListener[] { new IntegrationEventsListener() };
                x.EventListeners.PostCommitDeleteEventListeners = new IPostDeleteEventListener[] { new IntegrationEventsListener() };
                x.EventListeners.PostCollectionUpdateEventListeners = new IPostCollectionUpdateEventListener[] { new IntegrationEventsListener() };
                new SchemaUpdate(x).Execute(true, true);
            })
            .BuildSessionFactory();
    }

    private class OtherConventions : IHasManyConvention, IReferenceConvention
    {
        public void Apply(IOneToManyCollectionInstance instance)
        {
            instance.LazyLoad();
            instance.AsBag();
            instance.Cascade.SaveUpdate();
            instance.Inverse();
        }

        public void Apply(IManyToOneInstance instance)
        {
            instance.LazyLoad(Laziness.Proxy);
            instance.Cascade.None();
            instance.Not.Nullable();
        }
    }

    private class IncrementConvention : IIdConvention
    {
        public void Apply(IIdentityInstance instance)
        {
            instance.Column("Id");
            instance.GeneratedBy.Increment();
        }
    }
}

IPreInsertEventListener

public bool OnPreInsert(PreInsertEvent @event)
{
    var aggregateRoot = @event.Entity as AggregateRoot;
    if (aggregateRoot == null)
        return true;

    foreach (IEvent domainEvent in aggregateRoot.DomainEvents)
    {
        DomainEvents.Dispatch(domainEvent);
    }

    aggregateRoot.ClearDomainEvents();

    return true;
}

【问题讨论】:

  • session.Flush 被处决了吗?如果在_transaction.Commit 之前显式调用它会怎样?提交数据时,session.FlushMode 的值是多少?
  • @RomanArtiukhin 我相信Commit() 已经在后台调用了Flush()。但即使有明确的Flush(),也不会保留任何内容。提交时会话的 FlushMode 为 Auto
  • 为了确定......您的事件侦听器不会否决插入命令(例如 IPreInsertEventListener.OnPreInsert 由于某些原因返回 false)?
  • @RomanArtiukhin 我发布了IPreInsertEventListener 的代码。在运行时调用它返回true
  • @RomanArtiukhin 我终于找到了问题所在。走否决权插入之路确实是解决方案。详情见我的回答。

标签: c# sqlite nhibernate


【解决方案1】:

正如 Roman Artiukhin 指出的那样,我的 IPreInsertEventListener 一直通过返回 true 来否决插入。

棘手的是我认为这个监听器的返回值是表示成功/失败,而它表示否决 >.

因此我不得不更改为始终返回false,这意味着没有否决权

【讨论】:

    猜你喜欢
    • 2012-01-15
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 2014-11-27
    相关资源
    最近更新 更多