entity-framework - Entity Framework 加载关系

标签 entity-framework

我正在尝试加载关系,但由于我的设置,我似乎无法让它工作。

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

但首先要做的是:

模型

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);
    }
}

服务

接口(interface)

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; }
}

类(class):

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();
    }
}

存储库:

接口(interface):

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; }
}

类(class):

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) {}
}

那么,当转到 /values/{id}/secondvalues 时,如何才能最好地加载 SecondValues 呢?

更新

我设法让 include 工作,但没有让它在获取列表中运行。

将databaseItem重命名并更改为新接口(interface):

interface IEntity {
    int Id { get; }
}

然后在服务中更新为以下内容:

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);
    }
}

现在我可以在 Controller 中执行以下操作:

[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);
    }
}

但现在在请求 SecondValues 时会出现自引用循环

最佳答案

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

要保留 JSON 中的对象引用,请将以下代码添加到 Global.asax 文件中的 Application_Start 方法:

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

但是由于对象引用在 JSON 中不是标准的,因此如果不需要这些对象,最好不要将它们传输到客户端。只需将您的实体映射到 DTO 中并将其发送给客户端即可。

关于entity-framework - Entity Framework 加载关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35747471/

相关文章:

c# - EF 6 将 Where 子句添加到包含导航属性

c# - 在 EF 中不使用 NotMapped 属性执行 LINQ 查询

c# - EF Core 通过空检查破坏了构造函数的目的

c# - Entity Framework Code First 中的有效原始属性是什么?

.net - 使用 ADO.NET Entity Framework 从表中存在的值生成枚举

c# - EF 枚举所有被忽略的属性

c# - 使用 Entity Framework Fluent 语法或内联语法编写递归 CTE

c# - 单元测试 Entity Framework 将连接字符串设置为 bin 目录而不是 App_Data

c# - 在 ASP.NET Core 1.0 中使用 Entity Framework 7 搭建 SQL Server View ?

c# - Entity Framework AsNoTracking() 无限导航属性