gpt4 book ai didi

c# - Entity Framework - 全局 vs 局部上下文 vs 延迟加载

转载 作者:太空宇宙 更新时间:2023-11-03 18:31:32 25 4
gpt4 key购买 nike

最终答案:

我在 InRequestScope() 方法中使用了@WiktorZychla answer 和 Ninject 的组合。我重构了我的存储库以接受上下文注入(inject),然后在我的 NinjectControllerFactory 中添加了以下行:

ninjectKernel.Bind<EFDbContext>().ToSelf().InRequestScope();

(注意:我替换了:

ninjectKernel.Bind<ISellingLocation>().To<EFSellingLocationRepository>().InReque‌​stScope().WithConstructorArgument("context",new EFDbContext());

我在其中一条评论中提到的行,其中:

ninjectKernel.Bind<ISellingLocation>().To<EFSellingLocationRepository>();

因为它导致了错误)

我还使用 nuget 安装了 Ninject.MVC3,它创建了文件:“NinjectWebCommon.cs”,其中包含以下行:

DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));

虽然有人说这一行是可选的,但其他文章指出应该使用它以使 InRequestScope 在 MVC 站点中正常工作。

原问题:

我目前有几个 EF 存储库,每个都类似于以下内容:

public class EFCityRepository : ICityRepository
{
private EFDbContext context = new EFDbContext();

public bool Create(City cityToCreate)
{
...
}

public City Get(int cityID)
{
...
}
}

如您所见,现在我对所有操作都使用单一的全局 EFDbContext,从我读到的内容来看这是不好的 - 所以我尝试将它(在 Create、Get 和其他方法中)更改为“using”语句,类似于以下内容:

public City Get(int cityID)
{
using(EFDbContext context)
{
...some opeartions…
return entities;
}
}

现在我遇到了很多与实体延迟加载相关的问题,我不得不使用类似下面的方法:

context.Entry(getResult.FirstOrDefault()).Reference(x => x.Address).Load();
context.Entry(getResult.FirstOrDefault()).Reference(x => x.Agency).Load();
context.Entry(getResult.FirstOrDefault().Address).Reference(x => x.City).Load();

只是为了简单起见以我想要的方式工作,否则每次我尝试访问 Address 时,我都会得到:“ObjectContext 实例已被处理,不能再用于需要连接的操作” .当然,当上下文是全局的时,它工作正常。

我需要一些建议:我应该使用本地上下文并使用预加载而不是延迟加载吗?还是这里可以接受全局背景?

还有一个人到底是怎么想使用延迟加载的呢?正如我所见 - 我必须为使用某些存储库的每个操作编写单独的逻辑 - 或者我错了吗?

编辑 1:

@Askolein:

好的,目前我的应用程序包含几个子项目:

Common
Domain - here I have my repositories
Helpers
Utils
WebUI

我用来触发错误的存储库如下所示:

public interface ISellingLocation
{
KeyValuePair<bool, Exception> Create(SellingLocation sellingLocationToAdd);
KeyValuePair<SellingLocation, Exception> Get(int sellingLocationID);
KeyValuePair<bool, Exception> Update(SellingLocation sellingLocationToUpdate);
KeyValuePair<bool, Exception> Delete(int sellingLocationID);

KeyValuePair<List<SellingLocation>, Exception> GetAll();
KeyValuePair<List<SellingLocation>, Exception> GetAll(int agencyID);
KeyValuePair<List<SellingLocation>, Exception> GetFiltered(string filter);
KeyValuePair<List<SellingLocation>, Exception> GetFiltered(Expression<Func<SellingLocation, bool>> filter);

KeyValuePair<bool, Exception> DisableSellingLocations(List<int> sellingLocationsIDs);
}

以及 GetFiltered 方法的实现,如下所示:

public KeyValuePair<List<SellingLocation>, Exception> GetFiltered(Expression<Func<SellingLocation, bool>> filter)
{
Exception lastException = null;

using (var transaction = new TransactionScope())
{
using (EFDbContext context = new EFDbContext())
{
try
{
var getResult = context.SellingPoints.Where(filter).ToList();
//var getResult2 = getResult.ToList();

context.Entry(getResult.FirstOrDefault()).Reference(x => x.Address).Load();
context.Entry(getResult.FirstOrDefault()).Reference(x => x.Agency).Load();
context.Entry(getResult.FirstOrDefault().Address).Reference(x => x.City).Load();


transaction.Complete();

return new KeyValuePair<List<SellingLocation>, Exception>(getResult, lastException);
}
catch (Exception ex)
{
lastException = ex;

return new KeyValuePair<List<SellingLocation>, Exception>(new List<SellingLocation>(), ex);
}
}
}
}

我在我的 Controller 中调用这个方法是这样的:

var allSellingLocationsForCurrentUser = sellingLocationRepository.GetFiltered(x => x.IsEnabled);

if(allSellingLocationsForCurrentUser.Value == null)
{
AgencySalesSellingLocationsListViewModel agencySalesSellingLocationsListViewModel = new AgencySalesSellingLocationsListViewModel();

foreach (var item in allSellingLocationsForCurrentUser.Key)
{
agencySalesSellingLocationsListViewModel.aaData.Add(new AgencySalesSellingLocationsListViewModelRow()
{
ID = item.SellingLocationID,
DT_RowId = item.SellingLocationID.ToString(),
Name = item.Name,
City = item.Address.City.Name,
Street = item.Address.Street
});
}

return Json(agencySalesSellingLocationsListViewModel, JsonRequestBehavior.AllowGet);
}

我明白为什么我会收到错误,正如我之前所说 - 如果我明确告诉实体加载:Address、Agency 和 Address.City - 它会工作得很好。

@WiktorZychla:

我当前的 DataContext 如下所示:

public class EFDbContext : DbContext
{
public EFDbContext():base("DefaultConnection")
{

}

public DbSet<User> Users { get; set; }
public DbSet<UserData> UserDatas { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<SkillCategory> SkillCategories {get;set;}
public DbSet<Skill> Skills {get;set;}
public DbSet<SkillAnswer> SkillAnswers { get; set; }
//public DbSet<UserSkills> UserSkills { get; set; }
public DbSet<User2Skill> User2Skill { get; set; }
public DbSet<Agency> Agencies { get; set; }
public DbSet<UniversalDictionary> UniversalDictionaries { get; set; }
public DbSet<UserAddressTimeTable> UserAddressTimeTables { get; set; }
public DbSet<City> Cities { get; set; }
public DbSet<SellingLocation> SellingPoints { get; set; }
}

如果我理解正确 - 我将不得不封装我的 EFCityRepository 并使用类似的东西:

using(SomeContext context = new SomeContext())
{
EFCityRepository repository = new EFCityRepository(context);
var result = repository.Get(id);
...do some work...
}

是不是有点过分了?现在我使用 Ninject,并使用存储库接口(interface)(IUserRepository、IUserRepository 等)注入(inject)我的 Controller - 所以我的 Controller 方法像工作单元一样工作,如果我理解正确 - 我将不得不:将我的 DbContext 注入(inject)我的 Controller 方法,或者在 Controller 方法和存储库之间创建另一个层...我理解正确吗?

@宠儿:

正如我上面所说的——我将我的 Controller 方法视为工作单元……如果我要实现你建议的东西——我应该把它放在哪里?内部域或 WebUI?它必须是存储库和 Controller 之间的另一层,对吗?

谢谢大家的建议。

最好的问候

最佳答案

与其将上下文本地化到存储库方法中,不如换一种方式——使存储库独立于上下文:

public class EFCityRepository : ICityRepository
{
public EFCityRepository( EFDbContext context )
{
this.context = context;
}

private EFDbContext context;

public bool Create(City cityToCreate)
{
...
}

public City Get(int cityID)
{
...
}
}

这种方法为您提供了最大的灵 active 。您可以在存储库之间共享完全相同的上下文,每个存储库都可以有一个额外的上下文,无论如何。

对于基于 Web 的应用程序,通常的做法是让您的上下文“按请求”共享,这意味着在单个请求中使用完全相同的上下文,并且在请求管道的末尾处理它。

编辑:正如 Maess 所建议的,您绝对应该考虑通过依赖注入(inject)引擎(如 Unity 或 Ninject)半自动管理上下文生命周期的可能性。 DI 引擎还可以通过自动解析构造函数依赖性来显着帮助您。这是另一回事,但可能是您的架构向前迈出的坚实一步。

关于c# - Entity Framework - 全局 vs 局部上下文 vs 延迟加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21408746/

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