是否可以创建一个方法,通过引用在C#中使用实体框架返回实体的键?

时间:2016-07-28 09:13:40

标签: c# .net entity-framework architecture domain-driven-design

让我们假设有两个组件 - 核心和基础设施。在第一个中有接口和模型。它代表域模型并包含业务逻辑。模型建立在抽象上 - 只使用接口方法。

例如:

public interface INotificationService
{
   void Notify(User user, int modelId);
}

public interface IAuthorizationService
{
   void IsAuthorized(User user);
}

public interface IPersistenceService
{
   int AddSomeEntity(SomeModel model);
   void SaveChanges();
}

public interface ISomeModelManagementService
{
   void AddSomeModelAndNotify(User user, SomeModel model);
}

public class SomeModelManagementService : ISomeModelManagementService
{
   //Here would be constructor injection of INotificationService, IAuthorizationService and IPersistenceService

   void AddSomeModelAndNotify(User user, SomeModel model)
   {
      if(authorizationService.IsAuthorized(user))
      {
         int id = persistenceService.AddSomeEntity(model);
         persistenceService.SaveChanges();
         notificationService.Notify(user,id);
      }
      else
      {
         throw new UnauthorizedException();
      }
   }
}

上面的所有代码都将驻留在Core程序集中,并且没有引用接口的实现(ISomeModelManagementService除外)。

另一方面,在基础架构组件中,将存在基础架构相关问题的实现。例如,负责通过EMailNotificationService发送电子邮件或通过DbPersistenceService在数据库中映射和保存核心模型的代码。

我面临的问题是这种方法:

int AddSomeEntity(SomeModel model);

我希望实现批处理SaveChanges,而不是在每个命令(插入/更新/删除查询)之后立即实现保存实体。问题在于使用Entity Framework插入新实体。 EF将在DbContext上执行SaveChanges方法后更新其模型并返回主键。

我尝试按参考传递参数,但在SaveChanges之后没有更新。

可以使用dynamic返回而不是int来执行此操作,因此insert命令/ add方法将返回数据库模型(不是核心模型),然后可以获取id在SaveChanges执行之后它,但它是一个肮脏的解决方案。

是否可以通过方法返回对Entity Framework密钥的引用?

执行SaveChanges后是否有可能更新返回的ID?

int id = persistenceService.AddSomeEntity(model);
persistenceService.SaveChanges();
//Now I'd like to have id updated with the database key value

1 个答案:

答案 0 :(得分:0)

一种解决方案可能是返回id的包装器。由于包装器是引用类型,因此应在SaveChanges()之后更新Id。

// Interface for entities that only contains id.
public interface IIdentifiableEntity
{
    int Id { get; }
}

public interface INotificationService
{
   void Notify(User user, IIdentifiableEntity entity);
}

public interface IAuthorizationService
{
   void IsAuthorized(User user);
}

public interface IPersistenceService
{
   // Return the entity as a interface here...
   IIdentifiableEntity AddSomeEntity(SomeModel model);
   void SaveChanges();
}

public interface ISomeModelManagementService
{
   void AddSomeModelAndNotify(User user, SomeModel model);
}

public class SomeModelManagementService : ISomeModelManagementService
{
   //Here would be constructor injection of INotificationService, IAuthorizationService and IPersistenceService

   void AddSomeModelAndNotify(User user, SomeModel model)
   {
      if(authorizationService.IsAuthorized(user))
      {
         IIdentifiableEntity entity = persistenceService.AddSomeEntity(model);
         persistenceService.SaveChanges();
         // Pass reference entity to Notify.
         notificationService.Notify(user,entity);
      }
      else
      {
         throw new UnauthorizedException();
      }
   }
}

然后您的实体必须实现接口IIdentifiableEntity。我认为这可能是比使用dynamic更优雅的解决方案。积极的是它是一个非常小的接口,并没有真正暴露实体那么多(除了Id)。缺点是你的实体离开IPersistenceService的范围,这可能不是你想要的。

示例实现如下:

public class PersistentCustomerService : IPersistenceService
{
   public IIdentifiableEntity AddSomeEntity(Customer model)
   {
      var result = _context.Customers.Add(model);
      return result;
   }
}

public class Customer : IIdentifiableEntity
{
    public int Id {get;set;}
    public string Name {get;set;}
}