在从 asp.net 核心到 Angular 的过程中丢失继承类型
losing inheriting types on the way from asp.net core to Angular
我正在开发一个应用程序,在服务器端使用 asp.net core 2.2 和 ef core 2.2,在客户端使用 Angular 7。我无法弄清楚:
我有以下(简化)模型:
public abstract class LegalEntity
{
public int Id { get; set; }
public int Name { get; set; }
public Address FiscalAddress { get; set; }
}
public class Organisation : LegalEntity
{
public Organisation(){}
public Organisation(LegalEntityType legalEntityType, string name, Address fiscalAddress)
{
LegalEntityType = legalEntityType;
Name = name;
}
public LegalEntityType LegalEntityType { get; set; }
}
public class LegalEntityType
{
public int Id { get; set; }
public int Name { get; set; }
public LegalEntityType(){}
public LegalEntityType(string name)
{
Name = name;
}
}
public class Person : LegalEntity
{
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string Name => string.Format("{0} {1}", FirstName, LastName);
}
public class Gender
{
public int Id { get; set; }
public int Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public Customer(){}
public Customer(LegalEntity legalEntity)
{
LegalEntity = legalEntity;
}
public LegalEntity LegalEntity { get; set; }
}
当我return客户通过API客户实体时,有时LegalEntity是一个组织,有时是一个人。根据 returned 的类型(组织或个人),我希望将 属性 LegalEntityType(如果是组织)或 属性 性别(如果是个人)渲染到JSON 代码。这是我的第一个问题,下面让它们都为空:
.Include(o => o.Customer).ThenInclude(o => o.LegalEntity)
因为这不会加载仅存在于继承实体中的导航属性。在
的情况下,这是 JSON 字符串的摘录
人:
...
"customer": {
"legalEntity": {
"gender": null,
"firstName": "Denis",
"lastName": "Testmann",
"name": "Denis Testmann",
"id": 9
},
...
组织:
...
"customer": {
"legalEntity": {
"legalEntityType": null,
"name": "Companyname GmbH",
"id": 6
},
...
应该出来的是:
人:
...
"customer": {
"Person": {
"gender": null,
"firstName": "Denis",
"lastName": "Testmann",
"name": "Denis Testmann",
"id": 9
},
...
组织:
...
"customer": {
"Organisation": {
"legalEntityType": null,
"name": "Companyname GmbH",
"id": 6
},
...
直截了当:客户可以是个人或组织,实体(组织和个人)都继承自 LegalEntity,因此客户 属性“LegalEntity”有时是人,有时是人组织。当我呈现 JSON 时,必须维护特定类型。
希望我说得够清楚了 - 请原谅我拖了这么久,我想确定问题是否已被理解。
新答案
我通过 dotnet new console
通过 dotnet core 2.1 整理了以下 Program.cs:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
var list = new List<Customer>();
list.Add(new Customer(new Person { Gender = new Gender{ Name = "Male"}}));
list.Add(new Customer(new Organisation { LegalEntityType = new LegalEntityType{ Name = "GmbH"}}));
Console.WriteLine(JsonConvert.SerializeObject(list, Newtonsoft.Json.Formatting.Indented));
}
}
public abstract class LegalEntity
{
public int Id { get; set; }
public virtual string Name { get; set; }
public Address FiscalAddress { get; set; }
}
public class Organisation : LegalEntity
{
public Organisation(){}
public Organisation(LegalEntityType legalEntityType, string name, Address fiscalAddress)
{
LegalEntityType = legalEntityType;
Name = name;
}
public LegalEntityType LegalEntityType { get; set; }
}
public class LegalEntityType
{
public int Id { get; set; }
public string Name { get; set; }
public LegalEntityType(){}
public LegalEntityType(string name)
{
Name = name;
}
}
public class Person : LegalEntity
{
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string Name => string.Format("{0} {1}", FirstName, LastName);
}
public class Gender
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public Customer(){}
public Customer(LegalEntity legalEntity)
{
LegalEntity = legalEntity;
}
public LegalEntity LegalEntity { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
}
输出如下所示:
[
{
"Id": 0,
"LegalEntity": {
"Gender": {
"Id": 0,
"Name": "Male"
},
"FirstName": null,
"LastName": null,
"Name": " ",
"Id": 0,
"FiscalAddress": null
}
},
{
"Id": 0,
"LegalEntity": {
"LegalEntityType": {
"Id": 0,
"Name": "GmbH"
},
"Id": 0,
"Name": null,
"FiscalAddress": null
}
}
]
这看起来不错?也许检查您的 API 端点绑定器正在使用的序列化程序设置。
旧答案
如果 LegalEntity 在数据库中是真实的 table,您应该可以使用:
[ForeignKey("LegalEntity")]
public int LegalEntityId { get; set; }
在您的 Customer
定义中。
您还需要设置密钥:
public abstract class LegalEntity
{
[Key]
public int Id { get; set; }
public int Name { get; set; }
public Address FiscalAddress { get; set; }
}
如果 LegalEntity 不是真实的 table,则为 Person/Organisation
添加单独的导航
好的 - 找到了解决方案!
在服务器端,您必须使用
序列化 JSON 内容
SerializerSettings.TypeNameHandling = TypeNameHandling.Auto
您应该在 Startup.cs 文件中做什么:
services.AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
opt.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
})
在客户端你可以使用class-transformer (https://github.com/typestack/class-transformer)。
在我的示例中,客户 class - 其中 LegalEntity 可能是 Person 或 Organization 类型,如下所示:
public class Customer
{
public int Id { get; set; }
@Type( () => Object, {
discriminator: {
property: '$type',
subTypes: [
{value: Person, name: 'Your.Name.Space.Person, YourApp.Name'},
{value: Organisation, name: 'Your.Name.Space.Organisation, YourApp.Name'},
],
},
})
public LegalEntity LegalEntity { get; set; }
}
然后从普通的 javascript 对象构建客户 class 的实例,如下所示:
import { plainToClass } from 'class-transformer';
export class SomeClassInYourAngularApp implements OnInit {
customerList: Customer[];
ngOnInit() {
this.customerList = new Array<Customer>();
let u: any;
// lets get the plain js object form somewhere, ex. from a resolver
this.route.data.subscribe(data => {
u = data['customerList'].result;
});
u = plainToClass(Customer, u);
Object.assign(this.customerList, u);
}
就是这样!
我正在开发一个应用程序,在服务器端使用 asp.net core 2.2 和 ef core 2.2,在客户端使用 Angular 7。我无法弄清楚:
我有以下(简化)模型:
public abstract class LegalEntity
{
public int Id { get; set; }
public int Name { get; set; }
public Address FiscalAddress { get; set; }
}
public class Organisation : LegalEntity
{
public Organisation(){}
public Organisation(LegalEntityType legalEntityType, string name, Address fiscalAddress)
{
LegalEntityType = legalEntityType;
Name = name;
}
public LegalEntityType LegalEntityType { get; set; }
}
public class LegalEntityType
{
public int Id { get; set; }
public int Name { get; set; }
public LegalEntityType(){}
public LegalEntityType(string name)
{
Name = name;
}
}
public class Person : LegalEntity
{
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string Name => string.Format("{0} {1}", FirstName, LastName);
}
public class Gender
{
public int Id { get; set; }
public int Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public Customer(){}
public Customer(LegalEntity legalEntity)
{
LegalEntity = legalEntity;
}
public LegalEntity LegalEntity { get; set; }
}
当我return客户通过API客户实体时,有时LegalEntity是一个组织,有时是一个人。根据 returned 的类型(组织或个人),我希望将 属性 LegalEntityType(如果是组织)或 属性 性别(如果是个人)渲染到JSON 代码。这是我的第一个问题,下面让它们都为空:
.Include(o => o.Customer).ThenInclude(o => o.LegalEntity)
因为这不会加载仅存在于继承实体中的导航属性。在
的情况下,这是 JSON 字符串的摘录人:
...
"customer": {
"legalEntity": {
"gender": null,
"firstName": "Denis",
"lastName": "Testmann",
"name": "Denis Testmann",
"id": 9
},
...
组织:
...
"customer": {
"legalEntity": {
"legalEntityType": null,
"name": "Companyname GmbH",
"id": 6
},
...
应该出来的是:
人:
...
"customer": {
"Person": {
"gender": null,
"firstName": "Denis",
"lastName": "Testmann",
"name": "Denis Testmann",
"id": 9
},
...
组织:
...
"customer": {
"Organisation": {
"legalEntityType": null,
"name": "Companyname GmbH",
"id": 6
},
...
直截了当:客户可以是个人或组织,实体(组织和个人)都继承自 LegalEntity,因此客户 属性“LegalEntity”有时是人,有时是人组织。当我呈现 JSON 时,必须维护特定类型。
希望我说得够清楚了 - 请原谅我拖了这么久,我想确定问题是否已被理解。
新答案
我通过 dotnet new console
通过 dotnet core 2.1 整理了以下 Program.cs:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
var list = new List<Customer>();
list.Add(new Customer(new Person { Gender = new Gender{ Name = "Male"}}));
list.Add(new Customer(new Organisation { LegalEntityType = new LegalEntityType{ Name = "GmbH"}}));
Console.WriteLine(JsonConvert.SerializeObject(list, Newtonsoft.Json.Formatting.Indented));
}
}
public abstract class LegalEntity
{
public int Id { get; set; }
public virtual string Name { get; set; }
public Address FiscalAddress { get; set; }
}
public class Organisation : LegalEntity
{
public Organisation(){}
public Organisation(LegalEntityType legalEntityType, string name, Address fiscalAddress)
{
LegalEntityType = legalEntityType;
Name = name;
}
public LegalEntityType LegalEntityType { get; set; }
}
public class LegalEntityType
{
public int Id { get; set; }
public string Name { get; set; }
public LegalEntityType(){}
public LegalEntityType(string name)
{
Name = name;
}
}
public class Person : LegalEntity
{
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string Name => string.Format("{0} {1}", FirstName, LastName);
}
public class Gender
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public Customer(){}
public Customer(LegalEntity legalEntity)
{
LegalEntity = legalEntity;
}
public LegalEntity LegalEntity { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
}
输出如下所示:
[
{
"Id": 0,
"LegalEntity": {
"Gender": {
"Id": 0,
"Name": "Male"
},
"FirstName": null,
"LastName": null,
"Name": " ",
"Id": 0,
"FiscalAddress": null
}
},
{
"Id": 0,
"LegalEntity": {
"LegalEntityType": {
"Id": 0,
"Name": "GmbH"
},
"Id": 0,
"Name": null,
"FiscalAddress": null
}
}
]
这看起来不错?也许检查您的 API 端点绑定器正在使用的序列化程序设置。
旧答案
如果 LegalEntity 在数据库中是真实的 table,您应该可以使用:
[ForeignKey("LegalEntity")]
public int LegalEntityId { get; set; }
在您的 Customer
定义中。
您还需要设置密钥:
public abstract class LegalEntity
{
[Key]
public int Id { get; set; }
public int Name { get; set; }
public Address FiscalAddress { get; set; }
}
如果 LegalEntity 不是真实的 table,则为 Person/Organisation
添加单独的导航好的 - 找到了解决方案!
在服务器端,您必须使用
序列化 JSON 内容SerializerSettings.TypeNameHandling = TypeNameHandling.Auto
您应该在 Startup.cs 文件中做什么:
services.AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
opt.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
})
在客户端你可以使用class-transformer (https://github.com/typestack/class-transformer)。
在我的示例中,客户 class - 其中 LegalEntity 可能是 Person 或 Organization 类型,如下所示:
public class Customer
{
public int Id { get; set; }
@Type( () => Object, {
discriminator: {
property: '$type',
subTypes: [
{value: Person, name: 'Your.Name.Space.Person, YourApp.Name'},
{value: Organisation, name: 'Your.Name.Space.Organisation, YourApp.Name'},
],
},
})
public LegalEntity LegalEntity { get; set; }
}
然后从普通的 javascript 对象构建客户 class 的实例,如下所示:
import { plainToClass } from 'class-transformer';
export class SomeClassInYourAngularApp implements OnInit {
customerList: Customer[];
ngOnInit() {
this.customerList = new Array<Customer>();
let u: any;
// lets get the plain js object form somewhere, ex. from a resolver
this.route.data.subscribe(data => {
u = data['customerList'].result;
});
u = plainToClass(Customer, u);
Object.assign(this.customerList, u);
}
就是这样!