gpt4 book ai didi

c# - DbContext 可以强制执行过滤策略吗?

转载 作者:IT王子 更新时间:2023-10-29 04:09:23 30 4
gpt4 key购买 nike

我想将一个值传递给 DbContext 的构造函数,然后让该值对相关的 DbSet 强制执行“过滤”。这可能……还是有更好的方法?

代码可能如下所示:

class Contact {
int ContactId { get; set; }
int CompanyId { get; set; }
string Name { get; set; }
}

class ContactContext : DbContext {
public ContactContext(int companyId) {...}
public DbSet<Contact> Contacts { get; set; }
}

using (var cc = new ContactContext(123)) {
// Would only return contacts where CompanyId = 123
var all = (from i in cc.Contacts select i);

// Would automatically set the CompanyId to 123
var contact = new Contact { Name = "Doug" };
cc.Contacts.Add(contact);
cc.SaveChanges();

// Would throw custom exception
contact.CompanyId = 456;
cc.SaveChanges;
}

最佳答案

我决定实现一个自定义 IDbSet 来处理这个问题。要使用此类,您需要传入一个 DbContext、一个过滤器表达式和(可选)一个 Action 来初始化新实体,以便它们满足过滤器条件。

我已经测试了枚举集和使用 Count 聚合函数。它们都修改生成的 SQL,因此它们应该比在客户端过滤更有效。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;


namespace MakeMyPledge.Data
{
class FilteredDbSet<TEntity> : IDbSet<TEntity>, IOrderedQueryable<TEntity>, IOrderedQueryable, IQueryable<TEntity>, IQueryable, IEnumerable<TEntity>, IEnumerable, IListSource
where TEntity : class
{
private readonly DbSet<TEntity> Set;
private readonly IQueryable<TEntity> FilteredSet;
private readonly Action<TEntity> InitializeEntity;

public FilteredDbSet(DbContext context)
: this(context.Set<TEntity>(), i => true, null)
{
}

public FilteredDbSet(DbContext context, Expression<Func<TEntity, bool>> filter)
: this(context.Set<TEntity>(), filter, null)
{
}

public FilteredDbSet(DbContext context, Expression<Func<TEntity, bool>> filter, Action<TEntity> initializeEntity)
: this(context.Set<TEntity>(), filter, initializeEntity)
{
}

private FilteredDbSet(DbSet<TEntity> set, Expression<Func<TEntity, bool>> filter, Action<TEntity> initializeEntity)
{
Set = set;
FilteredSet = set.Where(filter);
MatchesFilter = filter.Compile();
InitializeEntity = initializeEntity;
}

public Func<TEntity, bool> MatchesFilter { get; private set; }

public void ThrowIfEntityDoesNotMatchFilter(TEntity entity)
{
if (!MatchesFilter(entity))
throw new ArgumentOutOfRangeException();
}

public TEntity Add(TEntity entity)
{
DoInitializeEntity(entity);
ThrowIfEntityDoesNotMatchFilter(entity);
return Set.Add(entity);
}

public TEntity Attach(TEntity entity)
{
ThrowIfEntityDoesNotMatchFilter(entity);
return Set.Attach(entity);
}

public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, TEntity
{
var entity = Set.Create<TDerivedEntity>();
DoInitializeEntity(entity);
return (TDerivedEntity)entity;
}

public TEntity Create()
{
var entity = Set.Create();
DoInitializeEntity(entity);
return entity;
}

public TEntity Find(params object[] keyValues)
{
var entity = Set.Find(keyValues);
if (entity == null)
return null;

// If the user queried an item outside the filter, then we throw an error.
// If IDbSet had a Detach method we would use it...sadly, we have to be ok with the item being in the Set.
ThrowIfEntityDoesNotMatchFilter(entity);
return entity;
}

public TEntity Remove(TEntity entity)
{
ThrowIfEntityDoesNotMatchFilter(entity);
return Set.Remove(entity);
}

/// <summary>
/// Returns the items in the local cache
/// </summary>
/// <remarks>
/// It is possible to add/remove entities via this property that do NOT match the filter.
/// Use the <see cref="ThrowIfEntityDoesNotMatchFilter"/> method before adding/removing an item from this collection.
/// </remarks>
public ObservableCollection<TEntity> Local { get { return Set.Local; } }

IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator() { return FilteredSet.GetEnumerator(); }

IEnumerator IEnumerable.GetEnumerator() { return FilteredSet.GetEnumerator(); }

Type IQueryable.ElementType { get { return typeof(TEntity); } }

Expression IQueryable.Expression { get { return FilteredSet.Expression; } }

IQueryProvider IQueryable.Provider { get { return FilteredSet.Provider; } }

bool IListSource.ContainsListCollection { get { return false; } }

IList IListSource.GetList() { throw new InvalidOperationException(); }

void DoInitializeEntity(TEntity entity)
{
if (InitializeEntity != null)
InitializeEntity(entity);
}
}
}

关于c# - DbContext 可以强制执行过滤策略吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5676280/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com