在 WCF RIA 中使用存储过程(Linq-to-SQL,而不是 EF) - Silverlight 4

发布于 2024-12-25 03:09:49 字数 1201 浏览 3 评论 0 原文

看在天地的份上,我真的希望有人能帮助我解决这个问题。似乎每个人都对 EF 有话可说,但对 Linq-to-SQL 却没什么可说的。

我正在尝试通过存储过程从表中获取一些数据,相信我,仅此而已。

  1. 我添加了 Linq-to-SQL 模型 (LAMP.dbml),并
  2. 从服务器资源管理器添加了存储过程 (getAffectedParcel)。 getAffectedParcel 采用 2 个字符串作为参数
  3. 构建应用程序。
  4. 添加了域服务类 (LAMPService)
  5. 选择 (LAMPDataContext) 作为数据上下文类(通常我会勾选生成元数据,但由于我不使用表,所以不启用勾选)
  6. LAMPService.cs 添加了以下函数:

    public IEnumerable <; getAffectedParcelResult > GetTheAffectedParcels(字符串 v, 字符串 vf)
    {
        返回 this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
    }
    
  7. 在 Silverlight 页面中添加了以下代码以尝试使用存储过程:

    LAMPContext db = new LAMPContext();
    
    尝试
    {
        var q = db.GetTheAffectedParcels("18606004005", "").Value;
    
        foreach(q 中​​的 getAffectedParcelResult GAP)
        {
           MessageBox.Show(GAP.Owner);
        }
    }
    catch(异常前)
    {
        MessageBox.Show(例如Message.ToString());
    }
    
  8. 构建并运行应用程序。出现错误,指出:

未将对象引用设置为对象的实例。

我已经尝试了约 1000,000 种方法来看看这东西是否有效,但无济于事。请不要告诉我使用 Entity Framework,我想使用 Linq-to-SQL。有人(任何人)可以帮我吗?

//胡迪尼

For the love of heaven and earth I really wish someone could help me out with this issue. It seems everyone has something to say about EF but nothing about Linq-to-SQL.

I am trying to grab some data from my table via a stored procedure, believe me, that's all.

  1. I added the Linq-to-SQL model (LAMP.dbml)
  2. added the stored procedure (getAffectedParcel) from the server explorer. getAffectedParcel takes 2 strings as parameters
  3. Build the application.
  4. Added a domain service class (LAMPService)
  5. Selected the (LAMPDataContext) as the data context class (normally I would tick generate metadata, but since I am not working with tables it's not enabled for ticking)
  6. Added the following function to the LAMPService.cs:

    public IEnumerable < getAffectedParcelResult > GetTheAffectedParcels(String v, String vf)
    {
        return this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
    }
    
  7. Added the following code to a Silverlight page in an attempt to consume the stored procedure:

    LAMPContext db = new LAMPContext();
    
    try
    {
        var q = db.GetTheAffectedParcels("18606004005", "").Value;
    
        foreach (getAffectedParcelResult GAP in q)
        {
           MessageBox.Show(GAP.Owner);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show (ex.Message.ToString());
    }
    
  8. Build and run application. An error occurs stating:

Object reference not set to an instance of an object.

I have tried ~1000,000 ways to see if this thing would work, but to no avail. Please don't tell me to use Entity Framework, I want to use Linq-to-SQL. Can someone (anyone) help me out here.

//houdini

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暖树树初阳… 2025-01-01 03:09:49

从 Silverlight 客户端调用存储过程发生在异步世界中。让我们考虑 AdventureWorks 数据库中的一个示例...

这是域服务方法的样子。它正在对数据库中名为“BillOfMaterials”的存储过程调用 EF。

public IQueryable<BillOfMaterial> GetBillOfMaterials()
{
    return this.ObjectContext.BillOfMaterials;
}

回到客户端,这里是设置调用的代码...

public GetSp()
{
    InitializeComponent();
    DomainService1 ds1 = new DomainService1();
    var lo = ds1.Load(ds1.GetBillOfMaterialsQuery());
    lo.Completed += LoCompleted;
}

首先,创建域服务,然后用它来加载存储过程的结果。在这种特殊情况下,其结果是“LoadOperation”的实例。这些事情是异步的,因此 LoadOperation 需要在完成时有一个回调。回调代码如下所示...

public ObservableCollection<BillOfMaterial> MyList { get; set; }
void LoCompleted(object sender, EventArgs e)
{
    LoadOperation lo = sender as LoadOperation;
    if(lo!=null)
    {
        MyList = new ObservableCollection<BillOfMaterial>();
        foreach(BillOfMaterial bi in lo.AllEntities)
        {
            MyList.Add(bi);
        }
        dataGrid1.ItemsSource = MyList;
    }
}

在此方法中,“发送者”被取消引用到 LoadOperation 实例中,然后可以访问数据库中的所有好东西。在这个简单的示例中,构建了一个列表并将其作为 ItemsSource 传递到 DataGrid。这有助于理解,但在实践中您可能会做其他事情。

那应该可以解决你的问题。 :)

关于 Silverlight 和 RIA,我能给出的最佳建议是在 AdventureWorks 中尝试过之前不要自己做任何事情。您只会浪费时间并把头撞到墙上。

Calling a stored procedure from the Silverlight client happens in the Async world. Let's consider an example from the AdventureWorks database...

Here's what the Domain Service method looks like. It is calling the EF on a stored procedure in the database called 'BillOfMaterials'.

public IQueryable<BillOfMaterial> GetBillOfMaterials()
{
    return this.ObjectContext.BillOfMaterials;
}

Back on the client side, here is the code for setting up the call...

public GetSp()
{
    InitializeComponent();
    DomainService1 ds1 = new DomainService1();
    var lo = ds1.Load(ds1.GetBillOfMaterialsQuery());
    lo.Completed += LoCompleted;
}

First, the Domain Service is created, and then it is used to load the results of the stored procedure. In this particular case, the result of this is an instance of 'LoadOperation'. These things are async, so the LoadOperation needs to have a callback for when it is finished. The callback code looks like this...

public ObservableCollection<BillOfMaterial> MyList { get; set; }
void LoCompleted(object sender, EventArgs e)
{
    LoadOperation lo = sender as LoadOperation;
    if(lo!=null)
    {
        MyList = new ObservableCollection<BillOfMaterial>();
        foreach(BillOfMaterial bi in lo.AllEntities)
        {
            MyList.Add(bi);
        }
        dataGrid1.ItemsSource = MyList;
    }
}

In this method, the 'sender' is dereferenced into the LoadOperation instance, and then all the goodies from the database can be accessed. In this trivial example, a list is built and passed to DataGrid as the ItemsSource. It's good for understanding, but you would probably do something else in practice.

That should solve your problem. :)

The best advice I can give on Silverlight and RIA is never do ANYTHING on your own until you have tried it in AdventureWorks. You will just waste your time and beat your head against the wall.

沫雨熙 2025-01-01 03:09:49

首先,您的 DomainService 代码似乎是为 Invoke() 而不是 Query() 编写的。您应该使用查询,因为它使您能够将数据更新回服务器。

解决方案:您应该在域服务上的 GetTheAffectedParcels 中添加 [Query] 属性。

[Query]
public IQueryable<Parcel> 
   GetTheAffectedParcels(string ParcelNumber, string LotNumber)
{
   // etc.
}

其次,RIA 服务需要知道哪个是 Parcel 类的主键。

解决方案:将 MetadataType 属性应用于 Parcel 类,这允许您间接向 Parcel 类添加元数据,因为它是由 Linq2Sql 生成的,并且您无法直接向 ParcelId 添加注释 - 它会被擦除。

[MetadataType(typeof(ParcelMetadata)]
public partial class Parcel
{
}

public class ParcelMetadata
{
    [System.ComponentModel.DataAnnotations.Key]
    public int ParcelId {get; set; }
}

第三,像这样修改你的客户端。相反,请在 Silverlight 客户端上尝试以下操作:

LAMPContext db = new LAMPContext();

try
{
    var q = db.GetTheAffectedParcelsQuery("18606004005", "");

    db.Load(q, (op) =>
    {
       if (op.HasError)
       {
            label1.Text = op.Error.Message;
            op.MarkErrorAsHandled();
       }
       else
       {
            foreach (var parcel in op.Entities)
            {
                // your code here
            }
       }
    }
}
catch (Exception ex)
{
    label1.Text = op.ex.Message;
}

Firstly, it seems like your DomainService code is written for Invoke() rather than Query(). You should use Query as it enables you to update data back to the server.

Solution: you should add a [Query] attribute to GetTheAffectedParcels on the domain service.

[Query]
public IQueryable<Parcel> 
   GetTheAffectedParcels(string ParcelNumber, string LotNumber)
{
   // etc.
}

Secondly, RIA Services needs to know which is the primary key on the Parcel class.

Solution: Apply a MetadataType attribute to the Parcel class, which allows you to add metadata to the Parcel class indirectly, since it is generated by Linq2Sql and you couldn't add annotations directly to the ParcelId - it'd get wiped away.

[MetadataType(typeof(ParcelMetadata)]
public partial class Parcel
{
}

public class ParcelMetadata
{
    [System.ComponentModel.DataAnnotations.Key]
    public int ParcelId {get; set; }
}

Thirdly, modify your client like this. Instead try this on the Silverlight client:

LAMPContext db = new LAMPContext();

try
{
    var q = db.GetTheAffectedParcelsQuery("18606004005", "");

    db.Load(q, (op) =>
    {
       if (op.HasError)
       {
            label1.Text = op.Error.Message;
            op.MarkErrorAsHandled();
       }
       else
       {
            foreach (var parcel in op.Entities)
            {
                // your code here
            }
       }
    }
}
catch (Exception ex)
{
    label1.Text = op.ex.Message;
}
甲如呢乙后呢 2025-01-01 03:09:49

非常感谢 Chui 和 Garry,他们几乎把我踢向了正确的方向:) [谢谢大家……哎哟]

这是我最终采取的程序:
-添加数据模型(LINQ2SQL)和域服务后,我创建了一个部分类[按照 Chui 的建议]并在其中包含以下元数据信息:

[MetadataTypeAttribute(typeof(getAffectedParcelResult.getAffectedParcelResultMetadata))]

public partial class getAffectedParcelResult
{
    internal sealed class getAffectedParcelResultMetadata
    {
        [Key]
        public string PENumber { get; set; }
    }
}

然后,调整域服务包括以下内容:

[查询]

    public IQueryable<getAffectedParcelResult> GetTheAffectedParcels(string v, string vf)
    {
        // IEnumerable<getAffectedParcelResult> ap = this.DataContext.getAffectedParcel(v, vf);

        return this.DataContext.getAffectedParcel(v, vf).AsQueryable();
    }

然后构建应用程序,之后 getAffectedParcelResult 存储过程出现在“数据源”面板中。然而我想通过代码访问它。因此,我通过以下方式在 silverlight [.xaml 页面] 中访问它:

LAMPContext db = new LAMPContext();

            var q = db.GetTheAffectedParcelsQuery("18606004005", "");
            db.Load(q, (op) =>
                {
                    if (op.HasError)
                    {
                        MessageBox.Show(op.Error.Message);
                        op.MarkErrorAsHandled();
                    }
                    else
                    {
                        foreach (getAffectedParcelResult gap in op.Entities)
                        {
                            ownerTextBlock.Text = gap.Owner.ToString();
                        }
                    }

                },false);

这很有效。问题是,我的存储过程返回一个复杂类型。因此,不可能将其映射到任何特定实体。
哦,顺便说一句,这篇文章也有帮助:
http://onmick.com/Home/tabid/154/articleType/ArticleView/articleId/2/Pulling-Data-from-Stored-Procedures-in-WCF-RIA-Services-for-Silverlight。 ASPX

Much thanks to Chui and Garry who practically kicked me in the right direction :) [thanks guys...ouch]

This is the procedure I finally undertook:
-After adding the data model(LINQ2SQL) and the domain service, I created a partial class [as suggested by Chui] and included the following metadata info therein:

[MetadataTypeAttribute(typeof(getAffectedParcelResult.getAffectedParcelResultMetadata))]

public partial class getAffectedParcelResult
{
    internal sealed class getAffectedParcelResultMetadata
    {
        [Key]
        public string PENumber { get; set; }
    }
}

Then, Adjusted the Domain Service to include the following:

[Query]

    public IQueryable<getAffectedParcelResult> GetTheAffectedParcels(string v, string vf)
    {
        // IEnumerable<getAffectedParcelResult> ap = this.DataContext.getAffectedParcel(v, vf);

        return this.DataContext.getAffectedParcel(v, vf).AsQueryable();
    }

Then Build the app, afterwhich the getAffectedParcelResult store procedure appeared in the Data Sources panel. I wanted to access this via code however. Therefore, I accessed it in silverlight [.xaml page] via the following:

LAMPContext db = new LAMPContext();

            var q = db.GetTheAffectedParcelsQuery("18606004005", "");
            db.Load(q, (op) =>
                {
                    if (op.HasError)
                    {
                        MessageBox.Show(op.Error.Message);
                        op.MarkErrorAsHandled();
                    }
                    else
                    {
                        foreach (getAffectedParcelResult gap in op.Entities)
                        {
                            ownerTextBlock.Text = gap.Owner.ToString();
                        }
                    }

                },false);

This worked nicely. The thing is, my stored procedure returns a complex type so to speak. As of such, it was not possible to map it to any particular entity.
Oh and by the way this article helped out as well:
http://onmick.com/Home/tabid/154/articleType/ArticleView/articleId/2/Pulling-Data-from-Stored-Procedures-in-WCF-RIA-Services-for-Silverlight.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文