如何在WebApi Odata中将对象(实体)作为参数传递

4
我跟随这个链接 在ASP.NET Web API中支持OData操作,我想像这样将我的对象/实体作为参数传递:
ActionConfiguration addNewPatient = builder.Entity<Patient>().Collection.Action("AddNewPatient");
        addNewPatient.Parameter<int>("hospId");
        addNewPatient.Parameter<int>("docId");
        addNewPatient.Parameter<Patient>("patient");
        addNewPatient.Returns<bool>();

但我遇到了这个问题:
System.ArgumentException: Invalid parameter type 'Patient'. 
A non-binding parameter type must be either Primitive, Complex, Collection of Primitive or a Collection of Complex.
Parameter name: parameterType

我尝试实现了这个功能。

   ActionConfiguration addNewPatient = builder.Entity<Patient>().Collection.Action("AddNewPatient");
    addNewPatient.Parameter<int>("hospId");
    addNewPatient.Parameter<int>("docId");
    var patientConfig = builder.StructuralTypes.OfType<EntityTypeConfiguration>().Single(x => x.Name == "Patient");
    addNewPatient.SetBindingParameter("patient", patientConfig, false);
    addNewPatient.Returns<bool>();

但是我不能再调用POST方法../odata/Patient/AddNewPatient了。

<FunctionImport Name="AddNewPatient" ReturnType="Edm.Boolean"      IsBindable="true">
<Parameter Name="patient" Type="Patient"/>
<Parameter Name="hospId" Type="Edm.Int32" Nullable="false"/>
<Parameter Name="docId" Type="Edm.Int32" Nullable="false"/>
</FunctionImport>

请帮我,我已经尝试了各种方法,但仍然没有成功。谢谢。


有人能帮帮我吗 :( - Quoc Nguyen
你试过 builder.Entity<Patient>().Action("AddNewPatient") 和 url odata/Patient('patient id')/AddNewPatient 吗? - Tasnim Reza
根据错误信息,您必须使用复杂类型。•复杂类型是一种无键的结构化类型。如果您的患者有一个键,它将不起作用。在您的模型中创建一个复杂的患者类型,并将其用作参数? - Watson
这个问题解决了吗?我也想发送一个实体到一个带有其他几个参数的操作中。当然是不可绑定的。 - Michael90
2个回答

3
您可以使用ActionConfiguration.EntityParameter()方法将实体绑定为参数传递给您的OData操作方法。
以下是一个示例:
ActionConfiguration validate = ModelBuilder.EntityType<TEntity>()
    .Collection.Action("Validate");
validate.Namespace = "Importation";
validate.EntityParameter<TEntity>(typeof(TEntity).Name);
validate.CollectionParameter<string>("UniqueFields");
validate.Returns<ValidationResult>();

请注意,ModelState不会根据提供的实体内容进行检查,并且会将任何缺失的属性设置为null。在您的模型中超过StringLength(x)注释的属性仍将通过。如果您希望在之后验证实体本身,请在操作方法中使用以下代码:

[HttpPost]
public virtual IHttpActionResult Validate(ODataActionParameters parameters)
{
//First we check if the parameters are correct for the entire action method
    if (!ModelState.IsValid)
    {
         return BadRequest(ModelState);
    }
    else
    {
         //Then we cast our entity parameter in our entity object and validate
         //it through the controller's Validate<TEntity> method
         TEntity Entity = (TEntity)parameters[typeof(TEntity).Name];
         Validate(Entity, typeof(TEntity).Name);
         if (!ModelState.IsValid)
         {
              return BadRequest(ModelState);
         }
         IEnumerable<string> uniqueFields = parameters["UniqueFields"] as IEnumerable<string>;
         bool result = Importer.Validate(Entity, uniqueFields);
         return Ok(result);
    }
}

请注意,您不仅限于在当前控制器中使用实体类型,当您要发布的实体与控制器的类型不匹配时,您更有可能使用此类实体后缀模式。例如,您可能会针对父对象发布子条目。 - Chris Schaller

0

直接将新的患者对象POST到/odata/Patient不是更好吗?毕竟这就是它存在的原因。

如果您想按照您描述的方式进行操作,您需要创建一个中间类型,并使该类型成为参数,然后在该类型和您的Edm类型之间进行转换。

var createPatient = modelBuilder.Entity<Patient>().Collection.Action("AddNewPatient");
createPatient.CollectionParameter<PatientPdo>("patient");

其中PatientPdo与Patient完全相同,只是删除了导航属性。这就是它抱怨的问题,可以说它一直都是Edm类型。

public class PatientPdo
    {
        public long Id{ get; set; }

        public Entity ToEdmEntity()
        {
            return new Patient
                {
                    Id= Id
                };
        }
    }

你能详细说明一下如何“只需POST对象”吗?我一直收到以下错误提示:非绑定参数类型必须是原始类型、复杂类型、原始类型的集合或复杂类型的集合。 - Jerther
-1 因为完全可以传递实体类型的对象,必须将参数定义为 EntityParameter<Patient>。我们使用 OData,以便避免为此类单一用途创建自定义数据传输对象。您提出了一个有效的观点,即在此控制器上使用默认的 POST 操作可能已经足够,但是有些情况下,您可能希望实现自定义替代操作以将数据发布到您的控制器。 - Chris Schaller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接