我正在尝试使用EntityFramework和OData v4构建API。
问题: 我需要一些额外的数据Item
,这些数据不在我的数据库中来创建新的Item
,但是oData赢了如果我在POST
调用中向我的JSON对象添加一些数据,则不会将其识别为[NotMapped]
。
我使用EntityFrameWork,因此,根据this question,我尝试在模型中使用数据注释.Ignore(t => t.extraProperty);
或extraProperty
。但oData似乎忽略了它。
我从这个POST获得的所有内容{
"name": "John Doe",
"extraProperty": "Random string"
}
是:
不支持非开放类型的非类型化值。
JSON我发来的POST电话:
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="MyApi.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Items">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.Int32" Nullable="false" />
<Property Name="name" Type="Edm.String" Nullable="false" />
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
$ metadata:
namespace MyApi.App_Start
{
public class OdataConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Items>("Items");
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
}
}
}
ODataConfig.cs
[Table("Item.Items")]
public partial class Items
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Items(){}
public int id { get; set; }
public string name { get; set; }
[NotMapped] // I already tried this, it's not working
public string extraProperty{ get; set; }
}
Items.cs
public partial class MyModel: DbContext
{
public MyModel()
: base("name=MyModel")
{
Database.SetInitializer<MyModel>(null);
}
public virtual DbSet<Items> Items{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// I also tried this but not working
modelBuilder.Entity<Items>()
.Ignore(e => e.extraProperty);
}
}
MyModel.cs
public class ItemsController : ODataController
{
private MyModeldb = new MyModel();
// POST: odata/Items
public async Task<IHttpActionResult> Post(Items items)
{
// items is always null when enterring here
// and this condition is always triggered
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Do some stuff with extraProperty here
db.Items.Add(items);
await db.SaveChangesAsync();
return Created(items);
}
}
MyController.cs
<package id="EntityFramework" version="6.2.0" targetFramework="net461" />
<package id="Microsoft.Data.Edm" version="5.8.3" targetFramework="net461" />
<package id="Microsoft.AspNet.OData" version="6.1.0" targetFramework="net45" />
<package id="Microsoft.Data.OData" version="5.8.3" targetFramework="net461" />
<package id="Microsoft.OData.Core" version="7.4.1" targetFramework="net45" />
<package id="Microsoft.OData.Edm" version="7.4.1" targetFramework="net45" />
部分package.config
extraProperty
我还想过制作一个拦截器,在调用post之前清除我的json,但根据this question,Web API OData不支持查询拦截器......
如何处理此错误并避免错误?我真的需要在POST方法中处理ColA ColB
AA1 Want1
AA2 Want2
AA3 Want3
,或者至少在此之前处理。{/ p>
答案 0 :(得分:1)
取决于您想要使用的&#34;额外数据&#34;因为,对于post方法使用输入模型更简单,用数据做你想做的事情,然后填写正确的EF Model属性。如果Annotations和FluentAPI不适合你,这将是最简单的解决方案
即
public partial class ItemsInput
{
public int id { get; set; }
public string name { get; set; }
public string extraProperty{ get; set; }
}
public async Task<IHttpActionResult> Post(ItemsInput itemsInput)
{
// This shouldn't be triggered anymore unless it's a valid error
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Do some stuff with extraProperty here
//Convert the input object to json string
var itemsInputJson = JsonConvert.SerializeObject(itemsInput);
//Load json string to the EF Model, this will fill up all compatible
//properties and ignore non-matching ones
Items items = JsonConvert.DeserializeObject<Items>(itemsInputJson);
db.Items.Add(items);
await db.SaveChangesAsync();
return Created(items);
}
&#13;
答案 1 :(得分:1)
在Items
课程中,删除
[NotMapped]
属性
public string extraProperty{ get; set; }
并在MyModel
类
modelBuilder.Entity<Items>()
.Ignore(e => e.extraProperty);
[NotMapped]
属性告诉OData
在序列化和反序列化Items类时忽略extraProperty
。但是,由于您要在POST
的{{1}}请求中使用它,因此您无法在此方案中使用ItemsController
属性,因此模型绑定会根据您的需要进行
答案 2 :(得分:0)
FluentAPI方式正常工作(多次测试)。 你能提供$元数据吗? 再次尝试删除NotMapped属性并在模型构建器上添加Ignore。
或者,您可以在GetEdmModel方法中将此属性添加到IEdmModel:
NSView
答案 3 :(得分:0)
您可以使用AutoMapper将所有内容映射到DTO,然后在控制器中手动应用QueryOptions。
注意:请记住包括
使用AutoMapper;
使用AutoMapper.QueryableExtensions;
public class ItemDTO
{
public int Id { get; set;}
public string Name { get; set;}
public string CustomProperty { get; set; }
}
public class ItemsController : ApiController
{
MyCustomContext _context;
public ItemsController(MyCustomContext context)
{
_context = context;
}
public IEnumerable<ItemDTO> Get(ODataQueryOptions<Item> q)
{
var itemsQuery = _context.Items.AsQueryable();
itemsQuery = q.ApplyTo(itemsQuery , new ODataQuerySettings()) as IQueryable<Item>;
var mapperConfiguration = this.GetMapperConfiguration();
return itemsQuery.ProjectTo<ItemDTO>(mapperConfiguration);
}
public IConfigurationProvider GetMapperConfiguration()
{
return new MapperConfiguration(x => x.CreateMap<Item, ItemDTO>().ForMember(m => m.CustomProperty, o => o.MapFrom(d => d.Id + "Custom")));
}
}
注意:您必须使用无法使用MapFrom
ResolveUsing
方法进行地图制作