[英]How to round trip an object with relation using asp .net web api, entity framework and json (code first)?
Using a .NET client app, I am trying to post an object A that includes a collection of objects B via asp .net web api JSON, have that create a LocalDB database, and store the data. 使用.NET客户端应用程序,我试图通过asp .net web api JSON发布一个包含对象B集合的对象A,创建一个LocalDB数据库并存储数据。 Then fetch object A again.
然后再次获取对象A.
The app includes 3 projects. 该应用程序包括3个项目。 A asp .net mvc 4 web api project, a .Net console app and a .Net class library.
一个asp .net mvc 4 web api项目,一个.Net控制台应用程序和一个.Net类库。 Both the asp .net app and console app reference the class library, which includes the class definitions for objects A and B.
asp .net应用程序和控制台应用程序都引用类库,其中包括对象A和B的类定义。
Class library: 班级图书馆:
public class Actor
{
public Actor()
{
this.Movies = new HashSet<Movie>();
}
public int ActorID { get; set; }
public string Name { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
}
public class Movie
{
public Movie()
{
this.Actors = new HashSet<Actor>();
}
public int MovieID { get; set; }
public string Name { get; set; }
public virtual ICollection<Actor> Actors { get; set; }
}
Console App: 控制台应用:
Movie movie = new Movie()
{
Name = "Dr. No"
};
Actor actor = new Actor()
{
Name = "Sean Connery"
};
movie.Actors.Add(actor);
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:3654");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.PostAsJsonAsync<Movie>("api/movies", movie).Result;
response.EnsureSuccessStatusCode();
response = client.GetAsync("api/movies/1").Result;
response.EnsureSuccessStatusCode();
Movie newMovie = response.Content.ReadAsAsync<Movie>().Result;
}
asp .net mvc DbContext: asp .net mvc DbContext:
public class MediaContext : DbContext
{
public MediaContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<Movie> Movies { get; set; }
public DbSet<Actor> Actors { get; set; }
}
Problem #1: It seems JSON doesn't like the circular reference, however if I don't add the collection to both objects, EF5 does not create a MoviesActors table to hold the reference. 问题#1:似乎JSON不喜欢循环引用,但是如果我不将集合添加到两个对象,EF5不会创建一个MoviesActors表来保存引用。
Problem #2: Even if I add the reference in the controller, when I return that object, it doesn't return it with the Actors. 问题#2:即使我在控制器中添加引用,当我返回该对象时,它也不会使用Actors返回它。 Eg I expected something like
我估计有类似的东西
Movie
{
MovieID = "1",
Name = "???",
Actors[] = { 1 }
}
But instead, Actors is just null. 但相反,Actors只是空的。
Update : Here is the self-referencing exception: 更新 :这是自引用异常:
ExceptionMessage=Self referencing loop detected with type 'System.Data.Entity.DynamicProxies.Movie_157D88BDC89E46A7CE4875C2970C7BBFB893972095EFA0745C2261AACC007969'. ExceptionMessage =使用类型'System.Data.Entity.DynamicProxies.Movie_157D88BDC89E46A7CE4875C2970C7BBFB893972095EFA0745C2261AACC007969'检测到的自引用循环。 Path '[0].Actors[0].Movies'.
路径'[0] .Actors [0] .Movies'。
I managed to work around this exception using the method at How did I solve the Json serializing circular reference error? 我设法使用如何解决Json序列化循环引用错误的方法解决此异常? and just disabling the proxy.
并且只是禁用代理。 That solves problem #1.
这解决了问题#1。 However when I get the Movies, they still come back with no Actors, even using Include("Actors").
然而,当我收到电影时,即使使用Include(“演员”),他们仍然会回来没有演员。 I can see the reference has been created correctly in the intermediate table in the LocalDb.
我可以看到在LocalDb的中间表中正确创建了引用。
Update 2 更新2
FINALLY figured this out, answer below. 最后想出来了,回答如下。
Thanks so much! 非常感谢!
After much searching I was finally able to resolve my issue. 经过多次搜索,我终于能够解决我的问题。 Originally I tried adding a [ScriptIgnore] tag to the Movies set, however I was using EF5 final which changed the default serializer to JSON .NET.
最初我尝试将[ScriptIgnore]标签添加到Movies集中,但是我使用EF5 final将默认序列化程序更改为JSON .NET。 I finally found that [ScriptIgnore] didn't work and I had to set [JsonIgnore] like this:
我终于发现[ScriptIgnore]没有用,我必须像这样设置[JsonIgnore]:
public class Actor
{
public int ActorID { get; set; }
public string Name { get; set; }
[JsonIgnore]
public virtual ICollection<Movie> Movies { get; set; }
}
public class Movie
{
public int MovieID { get; set; }
public string Name { get; set; }
public virtual ICollection<Actor> Actors { get; set; }
}
Doing that combined with the .Include("Actors") eager loading in the Get method finally solved my issue. 在Get方法中结合.Include(“Actors”)的热切加载最终解决了我的问题。
In summary I needed to: 总之,我需要:
Additionally I found for subsequent PUTs of the Movie object, where the Actors collection had changed, I had to manually change the RelationShip state on each child Actor to either Added/Deleted to make sure the related collection was updated. 另外我找到了Movie对象的后续PUT,其中Actors集合已经改变,我不得不手动将每个子Actor上的RelationShip状态更改为Added / Deleted以确保相关集合已更新。
About your comment: 关于你的评论:
Also, I'd be completely happy to remove the
public virtual ICollection<Movie> Movies { get; set; }
此外,我很乐意删除
public virtual ICollection<Movie> Movies { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
from the Actor class, however in doing that, EF wasn't generating the intermediate table in the LocalDb.public virtual ICollection<Movie> Movies { get; set; }
从Actor类,然而,在这样做,EF是不产生在的LocalDB中间表。
If you remove one of the collections EF assumes by convention that your relationship is a one-to-many relationship (which doesn't have an intermediate table, but only a foreign key in one of the tables) in contrast to the model with two collections where EF creates a many-to-many relationship (that has an intermediate table). 如果删除其中一个集合,EF假定您的关系是一对多关系(没有中间表,但只有一个表中的外键)与两个模型形成对比EF创建多对多关系(具有中间表)的集合。
However, you can override this convention using Fluent API and tell EF explicitly that the remaining collection belongs to a many-to-many relationship instead of a one-to-many. 但是,您可以使用Fluent API覆盖此约定,并明确告知EF其余集合属于多对多关系而不是一对多关系。 Having this model...
拥有这个模型......
public class Actor
{
//...
public int ActorID { get; set; }
public string Name { get; set; }
}
public class Movie
{
//...
public int MovieID { get; set; }
public string Name { get; set; }
public virtual ICollection<Actor> Actors { get; set; }
}
...you can define a many-to-many relationship this way: ...您可以通过以下方式定义多对多关系:
public class MediaContext : DbContext
{
//...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Movie>()
.HasMany(m => m.Actors)
.WithMany()
.Map(a =>
{
a.MapLeftKey("MovieID");
a.MapRightKey("ActorID");
a.ToTable("MovieActors"); // intermediate table
});
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.