我正在尝试加载关系,但由于我的设置,我似乎无法让它工作。
我禁用了延迟加载来修复循环异常。
但首先要做的是:
模型
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/