ASP.NET WebApi JSON响应和具有外键的实体

时间:2022-10-10 16:38:24

I'm working on WebApi project and I have 2 entities in my domain:
Street

我正在开发WebApi项目,我的域名中有2个实体:Street

public class Street
{
  public int ID { get; set; }
  public string Name { get; set; }
  public int StreetTypeID { get; set; }
  public virtual StreetType StreetType { get; set; }
}

and StreetType:

public class StreetType
{
  public int ID { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Street> Streets { get; set; }
}

I use FluenApi to map these entities:

我使用FluenApi来映射这些实体:

public class StreetTypeMap : EntityTypeConfiguration<StreetType>
{
  public StreetTypeMap()
  {
     HasKey(t => t.ID);
     Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
     Property(t => t.Name).IsRequired().HasMaxLength(50);
     HasMany(a => a.Streets).WithRequired(p => p.StreetType).HasForeignKey(p => p.StreetTypeID);
     ToTable("StreetType");
   }
 }

and the similar for Street entity.
Now I get JSON:

和街道实体类似。现在我得到JSON:

{
  "id":1,
  "name":"Street1",
  "streettypeid":3
}

How can I get the JSON like:

如何获得JSON:

{
  "id":1,
  "name":"Street1",
  "streettypeid":
   {
    "id":3,
    "name":"Type3"
   }
}

Or some similar structure. How can I accomplish this in .NET?

或者一些类似的结构。我怎样才能在.NET中实现这一目标?

My Controller:

StreetController : BaseApiController<Street>

and

    public class BaseApiController<T> : ApiController where T : BaseEntity
    {
        protected UnitOfWork unitOfWork = new UnitOfWork();

        protected IRepository<T> repository;

        public BaseApiController()
        {
            repository = unitOfWork.EFRepository<T>();
        }
        public virtual IQueryable<T> Get()
        {
          var entity = repository.Table;

          if (entity == null)
          {
              throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NoContent));
          }
          return entity;
      }

}

2 个解决方案

#1


2  

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

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

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

For more datail please read this article.

有关更多数据,请阅读本文。

Another way is try to use OData in your webapi. You have to install the OData Packages:

另一种方法是尝试在webapi中使用OData。您必须安装OData包:

Install-Package Microsoft.AspNet.Odata

Then you'll able yo use $expand that causes related entities to be included inline in the response.
You can leave all as is, but I think it will properly to add IgnoreDataMember (do not forget add using System.Runtime.Serialization;)

然后你就可以使用$ expand来导致相关实体被包含在响应内联中。您可以按原样保留所有内容,但我认为可以正确添加IgnoreDataMember(不要忘记使用System.Runtime.Serialization添加;)

public class StreetType
{
  public int ID { get; set; }
  public string Name { get; set; }
  [IgnoreDataMember]
  public virtual ICollection<Street> Streets { get; set; }
}

Also need to add attribute to you Get method:

还需要为你添加属性Get方法:

[EnableQuery]
public virtual IQueryable<T> Get()

After that you can create http-request like:

之后,您可以创建http请求,如:

http://blablabla/Street?$expand=StreetType

and get all Streets with their StreetType

并使用他们的StreetType获取所有Streets

#2


1  

You need to create a view model to return that has the included entity.

您需要创建一个视图模型以返回包含实体的视图模型。

Edit: here's a complete api controller method including proposed route.

编辑:这是一个完整的api控制器方法,包括建议的路线。

    [HttpGet, Route("/api/streets/{id:int:min(1)}")]
    public IHttpActionResult GetYourJsonData(int id)
    {
        try
        {
            //from your unit of work class
            return uow.GetEntities<Street>(x => x.ID == id)
                .FirstOrDefault()
                .Select(viewModel => new {
                    ID = viewModel.ID,
                    Name = viewModel.Name,
                    StreetTypeID = viewModel.StreetType //consider renaming this to streeytype and not street type id
                });
        }
        catch(Exception)
        {
             return InternalServerError();
        }
    }



//Edit: in your repo class
public IEnumerable<T> GetEntities<T>(Func<T, bool> predicate) where T : class
{
    return yourContext.Set<T>().Where(predicate);
}

#1


2  

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

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

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

For more datail please read this article.

有关更多数据,请阅读本文。

Another way is try to use OData in your webapi. You have to install the OData Packages:

另一种方法是尝试在webapi中使用OData。您必须安装OData包:

Install-Package Microsoft.AspNet.Odata

Then you'll able yo use $expand that causes related entities to be included inline in the response.
You can leave all as is, but I think it will properly to add IgnoreDataMember (do not forget add using System.Runtime.Serialization;)

然后你就可以使用$ expand来导致相关实体被包含在响应内联中。您可以按原样保留所有内容,但我认为可以正确添加IgnoreDataMember(不要忘记使用System.Runtime.Serialization添加;)

public class StreetType
{
  public int ID { get; set; }
  public string Name { get; set; }
  [IgnoreDataMember]
  public virtual ICollection<Street> Streets { get; set; }
}

Also need to add attribute to you Get method:

还需要为你添加属性Get方法:

[EnableQuery]
public virtual IQueryable<T> Get()

After that you can create http-request like:

之后,您可以创建http请求,如:

http://blablabla/Street?$expand=StreetType

and get all Streets with their StreetType

并使用他们的StreetType获取所有Streets

#2


1  

You need to create a view model to return that has the included entity.

您需要创建一个视图模型以返回包含实体的视图模型。

Edit: here's a complete api controller method including proposed route.

编辑:这是一个完整的api控制器方法,包括建议的路线。

    [HttpGet, Route("/api/streets/{id:int:min(1)}")]
    public IHttpActionResult GetYourJsonData(int id)
    {
        try
        {
            //from your unit of work class
            return uow.GetEntities<Street>(x => x.ID == id)
                .FirstOrDefault()
                .Select(viewModel => new {
                    ID = viewModel.ID,
                    Name = viewModel.Name,
                    StreetTypeID = viewModel.StreetType //consider renaming this to streeytype and not street type id
                });
        }
        catch(Exception)
        {
             return InternalServerError();
        }
    }



//Edit: in your repo class
public IEnumerable<T> GetEntities<T>(Func<T, bool> predicate) where T : class
{
    return yourContext.Set<T>().Where(predicate);
}