实体框架负载关系 [英] Entity Framework load relation

查看:103
本文介绍了实体框架负载关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试加载关系,但是由于我的设置,我似乎无法使其正常工作。



我禁用了延迟加载来修复循环



但首先要做的是:



模型

  public class DatabaseItem 
{
[Key]
public int Id {get;组;
}

public class Value:DatabaseItem
{
[必需]
public string Name {get;组; }
[必需]
public string State {get;组; }

[DefaultValue(Hidden)]
public string HiddenValue {get;组; }

public virtual List< SecondValue> SecondValues {get;组; }
}

public class SecondValue:DatabaseItem
{
public string Name {get;组; }
public string State {get;组; }

public virtual Value Value {get;组;
}

控制器

  public IHttpActionResult Get(int id)
{
Log.Debug(string.Format(获取id为{0} , ID));
try {
return Json(_apiService.Values.Get(id));
} catch(Exception e){
Log.Error(string.Format(Get value with id {0},id),e);
throw new Exception(string.Format(获取id为{0}的值,id),e);
}
}

[Route(values / {id} / secondvalues)]
public IHttpActionResult GetSecondValues(int id){
Log。 Debug(string.Format(获取第二个值为id {0},id));
try {
var test = _apiService.Values.Get(id);
//这里我应该得到SecondValues :)
return Json(test.SecondValues);
} catch(Exception e){
Log.Error(string.Format(获取id为0的值的第二个值,id),e);
throw new Exception(string.Format(获取id为0的值的第二个值,id),e);
}
}

服务



接口

  public interface IApiService 
{
IValueService价值{get; }
ISecondValueService SecondValues {get; }
}

public interface IValueService:IService< Value>,IObjectService< Value> {}
public interface ISecondValueService:IService< SecondValue>,IObjectService< SecondValue> {}

公共接口IService< T>
{
列表< T>的GetList();
T Get(int id);
bool存在(int id);
int Update(int id,T obj);
T Add(T obj);
void Delete(T obj);
}

public interface IObjectService< T>
{
T Find(T obj); b
$ b public interface IDalContext: }
ISecondValueRepository SecondValues {get;
}

 内部抽象类服务< TObject> :IService< TObject>其中TObject:class {
protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()。DeclaringType);
protected readonly IRepository< TObject> _repository;

protected Service(IRepository< TObject> repository){
_repository = repository;
}

public List< TObject> GetList(){
Log.Debug(string.Format(Getting {0},typeof(TObject)));
try {
return _repository.All()。ToList();
} catch(Exception e){
Log.Error(string.Format(Error Getting {0},typeof(TObject)),e);
throw new Exception(string.Format(Error Getting {0},typeof(TObject)),e);
}
}

public TObject Get(int id){
Log.Debug(string.Format(Getting {0},id:{1} ,typeof(TObject),id));
try {
return _repository.Find(id);
} catch(Exception e){
Log.Error(string.Format(Error Getting {0},id:{1},typeof(TObject),id),e);
throw new Exception(string.Format(Error Getting {0},id:{1},typeof(TObject),id),e);
}
}

public bool Exists(int id){
Log.Debug(string.Format(Checking existance {0},id:{1} ,typeof(TObject),id));
try {
return _repository.Contains(o =>(o as DatabaseItem).Id == id);
} catch(Exception e){
Log.Error(string.Format(Checking existance {0},id:{1},typeof(TObject),id),e);
throw new异常(string.Format(Checking exists; {0},id:{1},typeof(TObject),id),e);
}
}

public int Update(int id,TObject obj){
var json = new JavaScriptSerializer()。Serialize(obj);

Log.Debug(string.Format(Adding {0},{1},typeof(TObject),json));
try {
return _repository.Update(obj);
} catch(Exception e){
Log.Error(string.Format(Error Adding {0},{1}},typeof(TObject),json),e);
throw new Exception(string.Format(Error Adding {0},{1},typeof(TObject),json),e);
}
}

public abstract TObject Find(TObject obj);

public TObject Add(TObject obj){
var json = new JavaScriptSerializer()。Serialize(obj);

Log.Debug(string.Format(Adding {0},{1},typeof(TObject),json));
try {
var val = Find(obj);
return val? _repository.Create(OBJ);
} catch(Exception e){
Log.Error(string.Format(Error Adding {0},{1}},typeof(TObject),json),e);
throw new Exception(string.Format(Error Adding {0},{1},typeof(TObject),json),e);
}
}

public void Delete(TObject obj){
var json = new JavaScriptSerializer()。Serialize(obj);

Log.Debug(string.Format(Adding {0},{1},typeof(TObject),json));
try {
_repository.Delete(obj);
} catch(Exception e){
Log.Error(string.Format(Error Adding {0},{1}},typeof(TObject),json),e);
throw new Exception(string.Format(Error Adding {0},{1},typeof(TObject),json),e);
}
}
}

class ValueService:Service< Value>,IValueService {
public ValueService(IRepository< Value> repository):base ){}

public override Value Find(Value obj){
if(obj.Name == null || obj.HiddenValue == null || obj.State == null){
返回null;
}
return _repository.Find(obj1 => obj1.Name == obj.Name&& obj1.HiddenValue == obj.HiddenValue&& obj1.State == obj.State );
}
}

class SecondValueService:Service< SecondValue> ISecondValueService {
public SecondValueService(IRepository< SecondValue> repository):base(repository){}

public override SecondValue Find(SecondValue obj){
throw new NotImplementedException();
}
}

存储库

接口:

  public interface IRepository< T> :IDisposable where T:class 
{
IQueryable< T>所有();
IQueryable< T>过滤器(表达式< Func< T,bool>>谓词);
IQueryable< T> Filter< Key>(表达式< Func< T,bool>>> filter,out int total,int index = 0,int size = 50);
bool包含(表达式< Func< T,bool>>谓词);
T Find(params object [] keys);
T Find(Expression< Func< T,bool>>谓词);
T创建(T t);
void Delete(T t);
int Delete(Expression< Func< T,bool>>谓词);
int Update(T t);
int Count {get; }
}

类:

  public class Repository< TObject> :IRepository< TObject>其中TObject:class 
{
protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()。DeclaringType);
保护Db上下文;
private bool shareContext = false;

public Repository(){
Context = new Db();
}

public Repository(Db context){
Context = context;
}

//这里是IRepository< TObject>的所有实现
}

内部类ValueRepositroy:Repository< Value>,IValueRepository {
public ValueRepositroy(Db context):base(context){}
}

内部类SecondValueRepository:Repository< SecondValue>,ISecondValueRepository {
public SecondValueRepository(Db context):base(context){}
}
pre>

那么当去$ / values / $ / code code code> {id} / secondvalues



更新



我设法得到包含工作,而没有在获取列表中运行。



重命名并更改databaseItem到一个新的界面:

  interface IEntity {
int Id {get; }
}

然后更新到以下服务到:

 内部抽象类服务< TObject> :IService< TObject>其中TObject:class,IEntity 

public IQueryable< TObject> GetList(){
Log.Debug(string.Format(Getting {0},typeof(TObject)));
try {
return _repository.All();
} catch(Exception e){
Log.Error(string.Format(Error Getting {0},typeof(TObject)),e);
throw new Exception(string.Format(Error Getting {0},typeof(TObject)),e);
}
}

public IQueryable< TObject> Get(int id){
Log.Debug(string.Format(获取{0},id:{1},typeof(TObject),id));
try {
return _repository.All()。Where(o => o.Id == id);
} catch(Exception e){
Log.Error(string.Format(Error Getting {0},id:{1},typeof(TObject),id),e);
throw new Exception(string.Format(Error Getting {0},id:{1},typeof(TObject),id),e);
}
}

所以现在我可以在我的控制器中执行以下操作:

  [Secure(value.detail)] 
public IHttpActionResult Get(int id){
Log.Debug(string.Format(get value with id {0},id));
try {
return Json(_apiService.Values.Get(id).FirstOrDefault());
} catch(Exception e){
Log.Error(string.Format(Get value with id {0},id),e);
throw new Exception(string.Format(获取id为{0}的值,id),e);
}
}

[Route(values / {id} / secondvalues)]
public IHttpActionResult GetSecondValues(int id){
Log。 Debug(string.Format(获取第二个值为id {0},id));
try {
var test = _apiService.Values.Get(id).Include(value => value.SecondValues).FirstOrDefault();

return Json(test.SecondValues);
} catch(Exception e){
Log.Error(string.Format(获取id为0的值的第二个值,id),e);
throw new Exception(string.Format(获取id为0的值的第二个值,id),e);
}
}

但是,当请求自动引用循环时SecondValues

解决方案

默认情况下,JSON和XML格式化程序将所有对象写入值。如果两个属性引用相同的对象,或者同一个对象在集合中出现两次,则格式化程序将对象序列化两次。如果对象图包含循环,这是一个特别的问题,因为当它在图形中检测到一个循环时,串行器将抛出异常。



为了保留JSON中的对象引用,在 Global.asax 文件中的 Application_Start 方法中添加以下代码:

  var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; 
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;

但是由于对象引用不是JSON中的标准,所以不会传输更好的方法如果你不需要这些对象给客户端。只需将您的实体映射到DTO中,并将其发送给客户端。


I'm trying to load a relation, but due to my setup I can't seem to get it working.

I disabled lazy loading for fixing the looping exception.

But first things first:

Models

public class DatabaseItem 
{
    [Key]
    public int Id { get; set; }
}

public class Value : DatabaseItem
{
    [Required]
    public string Name { get; set; }
    [Required]
    public string State { get; set; }

    [DefaultValue("Hidden")]
    public string HiddenValue { get; set; }

    public virtual List<SecondValue> SecondValues { get; set; } 
}

public class SecondValue : DatabaseItem 
{
    public string Name { get; set; }
    public string State { get; set; }

    public virtual Value Value { get; set; }
}

Controller:

public IHttpActionResult Get(int id) 
{
    Log.Debug(string.Format("Getting value with id {0}", id));
    try {
        return Json(_apiService.Values.Get(id));
    } catch (Exception e) {
        Log.Error(string.Format("Getting value with id {0}", id), e);
        throw new Exception(string.Format("Getting value with id {0}", id), e);
    }
}

[Route("values/{id}/secondvalues")]
public IHttpActionResult GetSecondValues(int id) {
    Log.Debug(string.Format("Getting secondvalues for value with id {0}", id));
    try {
        var test = _apiService.Values.Get(id);
        // here I should get the SecondValues :)    
        return Json(test.SecondValues);
    } catch (Exception e) {
        Log.Error(string.Format("Getting secondvalues for value with id {0}", id), e);
        throw new Exception(string.Format("Getting secondvalues for value with id {0}", id), e);
    }
}

Services

Interfaces

public interface IApiService 
{
    IValueService Values { get; }
    ISecondValueService SecondValues { get; }
}

public interface IValueService : IService<Value>, IObjectService<Value> {}
public interface ISecondValueService : IService<SecondValue>, IObjectService<SecondValue> {}

public interface IService<T>
{
    List<T> GetList();
    T Get(int id);
    bool Exists(int id);
    int Update(int id, T obj);
    T Add(T obj);
    void Delete(T obj);
}

public interface IObjectService<T> 
{
    T Find(T obj);
}

public interface IDalContext : IUnitOfWork 
{
    IValueRepository Values { get; }
    ISecondValueRepository SecondValues { get; }
}

Classes:

internal abstract class Service<TObject> : IService<TObject> where TObject : class {
    protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    protected readonly IRepository<TObject> _repository;

    protected Service(IRepository<TObject> repository) {
        _repository = repository;
    }

    public List<TObject> GetList() {
        Log.Debug(string.Format("Getting {0}", typeof (TObject)));
        try {
            return _repository.All().ToList();
        } catch (Exception e) {
            Log.Error(string.Format("Error Getting {0}", typeof (TObject)), e);
            throw new Exception(string.Format("Error Getting  {0}", typeof (TObject)), e);
        }
    }

    public TObject Get(int id) {
        Log.Debug(string.Format("Getting {0}, id: {1}", typeof (TObject), id));
        try {
            return _repository.Find(id);
        } catch (Exception e) {
            Log.Error(string.Format("Error Getting {0}, id: {1}", typeof (TObject), id), e);
            throw new Exception(string.Format("Error Getting  {0}, id: {1}", typeof (TObject), id), e);
        }
    }

    public bool Exists(int id) {
        Log.Debug(string.Format("Checking existance {0}, id: {1}", typeof (TObject), id));
        try {
            return _repository.Contains(o => (o as DatabaseItem).Id == id);
        } catch (Exception e) {
            Log.Error(string.Format("Checking existance {0}, id: {1}", typeof (TObject), id), e);
            throw new Exception(string.Format("Checking existance  {0}, id: {1}", typeof (TObject), id), e);
        }
    }

    public int Update(int id, TObject obj) {
        var json = new JavaScriptSerializer().Serialize(obj);

        Log.Debug(string.Format("Adding {0}, {1}", typeof (TObject), json));
        try {
            return _repository.Update(obj);
        } catch (Exception e) {
            Log.Error(string.Format("Error Adding {0}, {1}}", typeof (TObject), json), e);
            throw new Exception(string.Format("Error Adding {0}, {1}", typeof (TObject), json), e);
        }
    }

    public abstract TObject Find(TObject obj);

    public TObject Add(TObject obj) {
        var json = new JavaScriptSerializer().Serialize(obj);

        Log.Debug(string.Format("Adding {0}, {1}", typeof (TObject), json));
        try {
            var val = Find(obj);
            return val ?? _repository.Create(obj);
        } catch (Exception e) {
            Log.Error(string.Format("Error Adding {0}, {1}}", typeof (TObject), json), e);
            throw new Exception(string.Format("Error Adding {0}, {1}", typeof (TObject), json), e);
        }
    }

    public void Delete(TObject obj) {
        var json = new JavaScriptSerializer().Serialize(obj);

        Log.Debug(string.Format("Adding {0}, {1}", typeof(TObject), json));
        try {
            _repository.Delete(obj);
        } catch (Exception e) {
            Log.Error(string.Format("Error Adding {0}, {1}}", typeof(TObject), json), e);
            throw new Exception(string.Format("Error Adding {0}, {1}", typeof(TObject), json), e);
        }
    }
}

class ValueService : Service<Value>, IValueService {
    public ValueService(IRepository<Value> repository) : base(repository) { }

    public override Value Find(Value obj) {
        if (obj.Name == null || obj.HiddenValue == null || obj.State == null) {
            return null;
        }
        return _repository.Find(obj1 => obj1.Name == obj.Name && obj1.HiddenValue == obj.HiddenValue && obj1.State == obj.State);
    }
}

class SecondValueService : Service<SecondValue>, ISecondValueService {
    public SecondValueService(IRepository<SecondValue> repository) : base(repository) {}

    public override SecondValue Find(SecondValue obj) {
        throw new NotImplementedException();
    }
}

Repositories:

Interfaces:

public interface IRepository<T> : IDisposable where T : class 
{
    IQueryable<T> All();
    IQueryable<T> Filter(Expression<Func<T, bool>> predicate);
    IQueryable<T> Filter<Key>(Expression<Func<T, bool>> filter, out int total, int index = 0, int size = 50);
    bool Contains(Expression<Func<T, bool>> predicate);
    T Find(params object[] keys);
    T Find(Expression<Func<T, bool>> predicate);
    T Create(T t);      
    void Delete(T t);
    int Delete(Expression<Func<T, bool>> predicate);
    int Update(T t);
    int Count { get; }
}

Classes:

public class Repository<TObject> : IRepository<TObject> where TObject : class 
{
    protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    protected Db Context;
    private bool shareContext = false;

    public Repository() {
        Context = new Db();
    }

    public Repository(Db context) {
        Context = context;
    }

    // Here are all the implementations of IRepository<TObject>
 }

internal class ValueRepositroy : Repository<Value>, IValueRepository {
    public ValueRepositroy(Db context) : base(context) { }
}

internal class SecondValueRepository :  Repository<SecondValue>, ISecondValueRepository {
    public SecondValueRepository(Db context) : base(context) {}
}

So how could I best load in the SecondValues when going to /values/{id}/secondvalues?

UPDATE

I managed to get the include working while not having it run in the get list.

Renamed and changed the databaseItem to a new interface:

interface IEntity {
    int Id { get; }
}

Then updated to the following in the Service to:

internal abstract class Service<TObject> : IService<TObject> where TObject : class, IEntity

public IQueryable<TObject> GetList() {
    Log.Debug(string.Format("Getting {0}", typeof (TObject)));
    try {
        return _repository.All();
    } catch (Exception e) {
        Log.Error(string.Format("Error Getting {0}", typeof (TObject)), e);
        throw new Exception(string.Format("Error Getting  {0}", typeof (TObject)), e);
    }
}

public IQueryable<TObject> Get(int id) {
    Log.Debug(string.Format("Getting {0}, id: {1}", typeof (TObject), id));
    try {
        return _repository.All().Where(o => o.Id == id);
    } catch (Exception e) {
        Log.Error(string.Format("Error Getting {0}, id: {1}", typeof (TObject), id), e);
        throw new Exception(string.Format("Error Getting  {0}, id: {1}", typeof (TObject), id), e);
    }
}

So now I can do the following in my controllers:

[Secure("value.detail")]
public IHttpActionResult Get(int id) {
    Log.Debug(string.Format("Getting value with id {0}", id));
    try {
        return Json(_apiService.Values.Get(id).FirstOrDefault());
    } catch (Exception e) {
        Log.Error(string.Format("Getting value with id {0}", id), e);
        throw new Exception(string.Format("Getting value with id {0}", id), e);
    }
}

[Route("values/{id}/secondvalues")]
public IHttpActionResult GetSecondValues(int id) {
    Log.Debug(string.Format("Getting secondvalues for value with id {0}", id));
    try {
        var test = _apiService.Values.Get(id).Include(value => value.SecondValues).FirstOrDefault();

        return Json(test.SecondValues);
    } catch (Exception e) {
        Log.Error(string.Format("Getting secondvalues for value with id {0}", id), e);
        throw new Exception(string.Format("Getting secondvalues for value with id {0}", id), e);
    }
}

But now getting a self-referencing loop when requesting the SecondValues

解决方案

By default, the JSON and XML formatters write all objects as values. If two properties refer to the same object, or if the same object appears twice in a collection, the formatter will serialize the object twice. This is a particular problem if your object graph contains cycles, because the serializer will throw an exception when it detects a loop in the graph.

To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
Newtonsoft.Json.PreserveReferencesHandling.All;

But because object references are not that standard in JSON, it would be a better approach to not to transfer these objects to the client if you don't need them. Just map your entities in a DTO and send that to the client.

这篇关于实体框架负载关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆