我可以将派生属性添加到EF实体并使其可用于微风吗?

时间:2013-11-15 08:14:19

标签: asp.net-web-api entity-framework-5 breeze

我首先使用现有数据库,EF5,Web API和Breeze的代码,之前我还没有使用过这些技术。我正在写自己的pocos。

我试图公开一个只读属性,需要多个表连接才能获取数据。如果我们只使用Web API,我们可以运行一些sql,填充属性并将一些JSON发送回客户端。

因为我们正在使用EF和微风这显然会发生很大变化。

例如:

    public class Employee
{
    [Key]
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [NotMapped]
    public string FooBar
    {
        get { return getFooBar(); }
    }

}
    private string getFooBar()
    {
        // Do stuff here
    }

这会将FooBar发送回JSON结果中的客户端,但因为它没有映射,因此不在元数据中,所以我似乎无法在Breeze中使用它。

我读过一些文章,说我可以在使用基于设计器的方法(即编辑edmx文件)时执行此操作,但如何首先使用代码完成?

我知道我可以在客户端扩展Breeze实体但是我不确定在Breeze创建了所有实体之后我将如何获得未映射的值。

我真正想要的是扩展我的代码第一个实体。我也模糊地理解这可能不符合EF理想,但我也很难理解我没有自由来定义什么是什么,什么不是我的员工的财产。

我不需要跟踪更改。我不需要保存。我似乎无法使用EF上下文提供程序加入(很多)表并获取数据,因为每个表的实体不共享主键而不从同一个类继承。

我认为this SO post here表示类似的东西,但它再一次表示生成的类。有没有办法做到这一点?感谢。

修改
在回答Wards的建议时,我尝试了一些测试。

我的客户端构造函数:

function Employee() {
    this.DisplayName = ""; // unmapped property  
};

我的控制器:

function TestController($scope, $routeParams) {
var manager = new breeze.EntityManager('breeze/employees');

var metadataStore = manager.metadataStore;
metadataStore.registerEntityTypeCtor("Employee", Employee);

var query = new breeze.EntityQuery()
    .from("Employees")
    .orderBy("FirstName");

manager.executeQuery(query).then(function (data) {

    // Check unmapped property name
    var employeeType = metadataStore.getEntityType("Employee");
    var unmapped = employeeType.unmappedProperties;
    alert(unmapped[0].name)     // Returns 'DisplayName'
    alert(employeeType.dataProperties[3].name) // Returns 'DisplayName'

    var prop = manager.metadataStore.getEntityType('Employee').getProperty('DisplayName');
    alert(prop.name) // Returns 'DisplayName'

    var first = data.results[0]
    var fullName = first.DisplayName
    alert(fullName) // Returns empty string                

    $scope.employees = data.results;
    $scope.$apply();

}).fail(function (e) {
    alert(e);
});
};

My Angular:

<div>
<ul>
    <li data-ng-repeat="employee in employees">
        {{employee.DisplayName}}
    </li>
</ul>
</div>

因此该属性似乎被正确设置为未映射的属性,但它只返回空字符串。如果我改变

this.DisplayName = ""; // unmapped property

this.DisplayName = "Foo"; // unmapped property

然后DisplayName总是包含“Foo”。有效负载中的值未应用于DisplayName

我错过了什么吗?

2 个答案:

答案 0 :(得分:0)

Extending Entities文档主题中解释的Breeze客户端非常简单:在自定义构造函数中定义一个未映射的属性并注册该构造函数。

var metadataStore = myEntityManager.metadataStore;

metadataStore .registerEntityTypeCtor("Employee", Employee);

function Employee () 
  this.FooBar = ""; // unmapped property
};

现在,Breeze元数据包含FooBar未映射属性的定义。服务器将向客户端发送FooBar的值,当Breeze从查询中实现Employee个实体时,它将填充该客户端Employee实体(未映射)属性。

如何获取服务器上的FooBar属性值取决于您。我对你的应用程序知之甚少。您向我们展示的是完全有效的Code First实体定义。

也许你问的是实体框架问题而不是微风问题。

答案 1 :(得分:0)

CassidyK讨论了in this SO answer的一种方法。这是代码片段。

 proto.initializeFrom = function (rawEntity) {
    // HACK:
    // copy unmapped properties from newly created client entity to the rawEntity.
    // This is so that we don't lose them when we update from the rawEntity to the target.
    // Something that will occur immediately after this method completes. 
    var that = this;
    this.entityType.unmappedProperties.forEach(function(prop) {
        var propName = prop.name;
        that[propName] = rawEntity[propName];  // CassidyK 
        //rawEntity[propName] = that[propName]; // Breeze 
    });

    if (!this._backingStore) {
        this._backingStore = { };
    }
};    

我不知道这是什么副作用。也许其中一个Breeze开发者可以更好地解释。

当Breeze配置为Angular时,这似乎只是一个问题。

IE

breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);