Использование хранимых процедур (Linq-to-SQL, а не EF) в WCF RIA - Silverlight 4 - PullRequest
2 голосов
/ 07 января 2012

Ради любви к небу и земле, я бы очень хотел, чтобы кто-нибудь помог мне с этим вопросом. Кажется, всем есть, что сказать об 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(String v, String vf)
    {
        return this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
    }
    
  7. Добавлен следующий код на страницу Silverlight в попытке использовать хранимую процедуру:

    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. Сборка и запуск приложения. Произошла ошибка о том, что

Ссылка на объект не установлена ​​для экземпляра объекта.

Я пробовал ~ 1000 000 способов проверить, будет ли это работать, но безрезультатно. Пожалуйста, не говорите мне использовать Entity Framework, я хочу использовать Linq-to-SQL. Может ли кто-нибудь (любой) помочь мне здесь.

// Гудини

Ответы [ 3 ]

1 голос
/ 07 января 2012

Вызов хранимой процедуры из клиента Silverlight происходит в мире Async. Давайте рассмотрим пример из базы данных AdventureWorks ...

Вот как выглядит метод доменной службы. Он вызывает EF для хранимой процедуры в базе данных под названием «BillOfMaterials».

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, а затем можно получить доступ ко всем вкусностям из базы данных. В этом тривиальном примере список создается и передается в DataGrid в качестве ItemsSource. Это хорошо для понимания, но вы, вероятно, будете заниматься чем-то другим на практике.

Это должно решить вашу проблему. :)

Лучший совет, который я могу дать в отношении Silverlight и RIA: никогда не делайте ничего самостоятельно, пока не попробуете это в AdventureWorks. Вы просто напрасно потратите время и ударите головой о стену.

0 голосов
/ 10 января 2012

Большое спасибо Чуи и Гарри, которые практически пинали меня в правильном направлении :) [спасибо, ребята ... ой]

Это процедура, которую я, наконец, предпринял: -После добавления модели данных (LINQ2SQL) и службы домена я создал частичный класс [как предложено Chui] и включил в него следующую информацию метаданных:

[MetadataTypeAttribute (TypeOf (getAffectedParcelResult.getAffectedParcelResultMetadata))] * +1005 *

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();
    }

Затем создайте приложение, после чего на панели «Источники данных» появилась процедура хранения getActedParcelResult. Однако я хотел получить доступ к этому через код. Поэтому я обратился к нему в silverlight [.xaml page] через следующее:

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

0 голосов
/ 07 января 2012

Во-первых, кажется, что ваш код DomainService написан для Invoke (), а не Query (). Вам следует использовать Query, поскольку он позволяет обновлять данные обратно на сервер.

Решение: вы должны добавить атрибут [Query] к GetTheActedParcels в доменной службе.

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

Во-вторых, RIA Services необходимо знать, какой первичный ключ в классе 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;
}
...