小编Dem*_*o78的帖子

覆盖Entity Framework 5 Code Code中的SaveChanges以复制旧旧库的行为

我们公司提供一套操作数据库中数据的各种应用程序.每个应用程序都有其特定的业务逻辑,但所有应用程序共享业务规则的公共子集.常见的东西包含在一堆用C++编写的遗留COM DLL中,它们使用"经典ADO"(它们通常调用存储过程,有时它们使用动态SQL).这些DLL中的大多数都具有基于XML的方法(更不用说基于专有格式的方法!)来创建,编辑,删除和检索对象,还有额外的操作,例如快速复制和转换许多实体的方法.

中间件DLL现在已经很老了,我们的应用程序开发人员需要一个新的面向对象(不是面向xml)的中间件,可以很容易地被C#应用程序使用.该公司的许多人都说我们应该忘记旧的范例,转而采用新的酷炫的东西,比如Entity Framework.他们对POCO的简单性很感兴趣,他们希望使用LINQ来检索数据(基于Xml的DLL查询方法不是那么容易使用,并且永远不会像LINQ那样灵活).

所以我正在尝试为简化场景创建一个模型(真实场景要复杂得多,在这里我只发布一个简化场景的简化子集!).我正在使用Visual Studio 2010,实体框架5代码优先,SQL Server 2008 R2.如果我犯了愚蠢的错误,请怜悯,我是Entity Framework的新手.由于我有许多不同的疑虑,我会将它们分别发布.这是第一个.传统的XML方法有这样的签名:

    bool Edit(string xmlstring, out string errorMessage)
Run Code Online (Sandbox Code Playgroud)

使用这样的格式:

<ORDER>
    <ID>234</ID>
    <NAME>SuperFastCar</NAME>
    <QUANTITY>3</QUANTITY>
    <LABEL>abc</LABEL>
</ORDER>
Run Code Online (Sandbox Code Playgroud)

Edit方法实现了以下业务逻辑:当Quantity更改时,必须对具有相同Label的所有Orders应用"自动缩放".例如,有三个订单:OrderA的数量= 3,标签= X.订单B的数量= 4,标签= X.订单C的数量= 5,标签= Y.我调用Edit方法为OrderA提供新的数量= 6,即我将OrderA的数量加倍.然后,根据业务逻辑,OrderB的数量必须自动加倍,并且必须变为8,因为OrderB和OrderA具有相同的标签.不得更改OrderC,因为它具有不同的标签.

我如何使用POCO类和实体框架复制它?这是一个问题,因为旧的Edit方法一次只能更改一个订单,而实体框架可以在调用SaveChanges时更改大量订单.此外,对SaveChanges的单次调用也可以创建新的订单.临时假设,仅适用于此测试:1)如果同时更改了许多订单数量,并且所有这些订单数量的比例因子都不相同,则不进行缩放; 2)新添加的订单即使具有相同的缩放订单标签也不会自动缩放.

我试图通过重写SaveChanges来实现它.

POCO课程:

using System;

namespace MockOrders
{
    public class Order
    {
        public Int64 Id { get; set; }
        public string Name { get; set; }
        public string Label { get; set; }
        public decimal Quantity { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

迁移文件(创建索引):

namespace MockOrders.Migrations
{
    using …
Run Code Online (Sandbox Code Playgroud)

c# entity-framework savechanges code-first entity-framework-5

11
推荐指数
1
解决办法
5017
查看次数

CoInitializeEx在COM对象内部调用时返回S_OK

前段时间,我不得不修改一个旧的COM DLL(Visual C++ 2010,ATL),将它从"Apartment"线程模型迁移到"Both",即现在可以从STA和MTA线程调用它而无需序列化调用(当然,我不得不为共享数据添加内部同步.当从.NET应用程序通过Interop调用我的DLL时,这会在将COM事件(连接点)转换为.NET事件时导致问题(即使在.NET应用程序中我也必须支持STA和MTA).为了解决这些问题,我改变了触发事件的方式.

1)如果在STA上下文中调用DLL,它就像以前一样工作,即它创建一个不可见的窗口,然后,当必须引发事件时,它调用PostMessage到该窗口,然后主STA线程调用实际的事件 - 触发代码,即CProxy_IMyEventFiringInterface成员函数(CProxy_IMyEventFiringInterface派生自IConnectionPointImpl).

2)如果在MTA上下文中调用DLL,我没有主COM线程,我不能做PostMessage,所以我使用我创建的自定义线程,让该线程调用IConnectionPointImpl函数.

但AFAIK没有Windows API可以检测调用线程是STA还是MTA.许多网站都建议像这样使用CoInitializeEx:

HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
switch(hr)
{
    case S_FALSE:  // we are in a Multi-Threaded Apartment (MTA)
    CoUninitialize(); // each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize
    break;
    case RPC_E_CHANGED_MODE:  // we are in a Single-Threaded Apartment (STA)
    break;
    default:  // IMPOSSIBLE!!!!
}
Run Code Online (Sandbox Code Playgroud)

我决定将此调用放在CMyComComponent :: FinalConstruct中的CoInitializeEx中.一切都很好......直到今天.在客户场景中,我从我的跟踪工具中看到,对于某个.NET EXE应用程序(我没有源代码),上面的代码最终会出现在默认分支中,因为CoInitializeEx返回了S_OK.这怎么可能?Microsoft文档说S_OK意味着"COM库已在此线程上成功初始化",但我是INSIDE COM对象,COM库必须已经初始化!顺便说一句,默认分支不会关闭应用程序,但是,由于返回了S_OK,它调用了CoUninitialize(每次成功调用CoInitialize或CoInitializeEx,包括任何返回S_FALSE的调用,必须通过对CoUninitialize的相应调用来平衡)然后DLL继续假定STA(后见之明的错误移动).但它不是STA:事实上,后来的Pos​​tMessage返回FALSE.

我可以简单地更改代码以使用MTA作为默认值,如果CoInitializeEx(NULL,COINIT_MULTITHREADED)返回S_OK,我应该从一开始就做到了.但我也希望确保这是正确的做法,以避免将来出现进一步的问题.非常感谢Demetrio

c++ com atl apartments com-interop

6
推荐指数
1
解决办法
3744
查看次数