UnitOfWork / Repository设计模式和实体框架级联删除

时间:2016-05-03 14:36:18

标签: c# entity-framework

目前我们使用的UnitOfWork设计模式是我们无法改变的。 通用存储库类如下所示:

public class Repository<T> : IDisposable, IRepository<T> where T : class
{

    // Create our private properties
    private readonly DbContext context;
    private readonly DbSet<T> dbEntitySet;

    /// <summary>
    /// Default constructor
    /// </summary>
    /// <param name="context">The database context</param>
    public Repository(DbContext context)
    {

        // If no context is supplied, throw an error
        if (context == null)
            throw new ArgumentNullException("context");

        // Assign our context and entity set
        this.context = context;
        this.dbEntitySet = context.Set<T>();
    }

    /// <summary>
    /// Allows the execution of stored procedures
    /// </summary>
    /// <typeparam name="T">The entity model</typeparam>
    /// <param name="sql">The name of the stored procedure</param>
    /// <param name="parameters">Option list of parameters</param>
    /// <returns></returns>
    public DbRawSqlQuery<T> SQLQuery(string sql, params object[] parameters)
    {
        return this.context.Database.SqlQuery<T>(sql, parameters);
    }

    /// <summary>
    /// Gets all the entities
    /// </summary>
    /// <param name="includes">Option includes for eager loading</param>
    /// <returns></returns>
    public IQueryable<T> GetAll(params string[] includes)
    {
        IQueryable<T> query = this.dbEntitySet;
        foreach (var include in includes)
            query = query.Include(include);

        return query;
    }

    /// <summary>
    /// Creates an entity
    /// </summary>
    /// <param name="model"></param>
    public void Create(T model)
    {
        this.dbEntitySet.Add(model);
    }

    /// <summary>
    /// Updates an entity
    /// </summary>
    /// <param name="model"></param>
    public void Update(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Modified;
    }

    /// <summary>
    /// Removes an entity
    /// </summary>
    /// <param name="model"></param>
    public void Remove(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Deleted;
    }

    /// <summary>
    /// Dispose method
    /// </summary>
    public void Dispose()
    {
        this.context.Dispose();
    }

,服务看起来像这样:

public class Service<T> where T : class
{
    private readonly IUnitOfWork unitOfWork;
    private readonly IRepository<T> repository;

    protected IUnitOfWork UnitOfWork
    {
        get { return this.unitOfWork; }
    }

    protected IRepository<T> Repository
    {
        get { return this.repository; }
    }

    public Service(IUnitOfWork unitOfWork)
    {
        if (unitOfWork == null)
            throw new ArgumentNullException("unitOfWork");

        this.unitOfWork = unitOfWork;
        this.repository = unitOfWork.GetRepository<T>();
    }
}

并且UnitOfWork类看起来像这样:

/// <summary>
/// Used to handle the saving of database changes
/// </summary>
/// <typeparam name="TContext"></typeparam>
public class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext, new()
{

    // Private properties
    private readonly DbContext context;
    private Dictionary<Type, object> repositories;

    // Public properties
    public DbContext Context { get { return this.context; } }

    /// <summary>
    /// Default constructor
    /// </summary>
    public UnitOfWork()
    {
        this.context = new TContext();
        repositories = new Dictionary<Type, object>();
    }

    /// <summary>
    /// Gets the entity repository
    /// </summary>
    /// <typeparam name="TEntity">The entity model</typeparam>
    /// <returns></returns>
    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {

        // If our repositories have a matching repository, return it
        if (repositories.Keys.Contains(typeof(TEntity)))
            return repositories[typeof(TEntity)] as IRepository<TEntity>;

        // Create a new repository for our entity
        var repository = new Repository<TEntity>(context);

        // Add to our list of repositories
        repositories.Add(typeof(TEntity), repository);

        // Return our repository
        return repository;
    }

    /// <summary>
    /// Saves the database changes asynchronously
    /// </summary>
    /// <returns></returns>
    public async Task SaveChangesAsync()
    {
        try
        {

            // Save the changes to the database
            await this.context.SaveChangesAsync();

            // If there is an error
        } catch (DbEntityValidationException ex) {

            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage);

            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);

            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }

    /// <summary>
    /// Dispose
    /// </summary>
    public void Dispose()
    {
        this.context.Dispose();
    }
}

现在我有一个 ProductService ,如下所示:

/// <summary>
/// Handles all product related methods
/// </summary>
public class ProductService : Service<Product>
{

    /// <summary>
    /// The default constructor
    /// </summary>
    /// <param name="unitOfWork"></param>
    public ProductService(IUnitOfWork unitOfWork)
        : base(unitOfWork)
    {
    }

    /// <summary>
    /// Gets all products
    /// </summary>
    /// <param name="includes">Optional eager loading includes</param>
    /// <returns></returns>
    public async Task<List<Product>> GetAllAsync(params string[] includes)
    {

        // Return as an asynchronous list
        return await this.Repository.GetAll(includes).ToListAsync();
    }

    /// <summary>
    /// Gets a single product by id
    /// </summary>
    /// <param name="id">The id of the product</param>
    /// <param name="includes">Optional eager loading includes</param>
    /// <returns></returns>
    public async Task<Product> GetAsync(int id, params string[] includes)
    {
        var models = await this.GetAllAsync(includes);
        return models.Where(model => model.Id == id).SingleOrDefault();
    }

    /// <summary>
    /// Create a product
    /// </summary>
    /// <param name="model">The product model</param>
    public void Create(Product model)
    {

        // Create a team
        this.Repository.Create(model);
    }

    /// <summary>
    /// Update a product
    /// </summary>
    /// <param name="model">The product model</param>
    public void Update(Product model)
    {

        // Update a team
        this.Repository.Update(model);
    }

    /// <summary>
    /// Delete a product
    /// </summary>
    /// <param name="model">The product model</param>
    public void Remove(Product model)
    {

        // Remove a team
        this.Repository.Remove(model);
    }
}

我已将Code First数据库设置为在删除产品时使用Cascading Delete。设置了相当多的1到1个表关系。如果我使用SQL Management Studio,我可以手动从数据库中删除产品,它将删除所有相关条目。 但是,如果我尝试从我的应用程序中删除它,我会收到此错误:

  

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

理想情况下,我想循环遍历泛型类的子项(所以在 Reposity 类中)并检查是否为该实体启用了级联删除,如果是,我想删除它。 如果没有,什么都不做。

有没有人知道这是否可行或者知道另一个不涉及丢弃UnitOfWork设计模式的解决方案?

0 个答案:

没有答案