2009-03-25 4 views
0

У меня есть текстовый файл с заполнителями, например:Петля через значения поля LINQ

Благодарим вас за ваш заказ [OrderNo]. Ваш заказ будет отправлен: [Имя] [Street1] [Street2] и т.д.

Заполнителей являются именами полей в базе данных, окруженные скобками.

Я хочу, чтобы получить одну запись из базы данных, как:

порядка вар = (от о в testContext.OrderTables где o.OrderID == идентификатор выбрать о) Одиночная();

Тогда я хотел бы иметь возможность прокручивать объект заказа и получать имя поля, а его значение заполнять заполнителем.

Возможно ли это?

ответ

0

Как об этом:

 

void Main() 
{ 
    var text = "Thank you for your order [OrderNo]. Your order will be shipped to: [Name] [Street1] [Street2]"; 

    var order = new Order() {OrderNo = 1, Name="NameA", Street1 = "Address1A", Street2="Addres2A"}; 

    var splitted = text.Split(']').ToList(); 

    var orderType = (new Order()).GetType(); 

    var newText = text; 
    splitted.ForEach(p => 
    { 
     string field = p.Substring(p.IndexOf('[') + 1); 
     if (!string.IsNullOrEmpty(field)) 
     { 
      var result = orderType.GetProperty(field).GetValue(order, null); 
      //var method = orderType.GetMethod("get_"+field); 
      //var result = method.Invoke(o, null); 
      newText = newText.Replace("[" + field + "]", result.ToString()); 
     } 
    }); 
    Console.WriteLine(newText); 
} 


public class Order 
{ 
    public Order() 
    {} 

    public int OrderNo {get; set;} 
    public string Name {get; set;} 
    public string Street1 {get; set;} 
    public string Street2 {get; set;} 
} 
 

Я не уверен, если мне это нравится, но она работает. :-)

+0

Klinger похоже, что он отлично подойдет. Как я могу изменить это, чтобы иметь только один заказ - вместо списка Я просто перебираю одну запись (это приложение, а не заказ), поэтому мне нужен только один. – 2009-03-25 19:15:03

+0

Сэм, я отредактировал ответ, но я не уверен, что это то, о чем вы просите. – Klinger

1

Возможно, вы сможете сделать это с помощью .GetType(), а затем использовать отражение, чтобы получить индивидуальные свойства и их значения.

1

Вы не можете использовать LINQ напрямую, чтобы перебирать свойства объекта, поскольку нет перечисления свойств объекта, доступных на объекте. Однако вы можете использовать Reflection для получения свойств объекта. LINQ может пригодиться при просмотре этих данных, чтобы найти подходящий объект для вашего заполнителя.

public Dictionary<string,object> 
    ValuesForPlaceHolders(object obj, 
          IEnumerable<string> placeHolders) 
{ 
    var map = new Dictionary<string,object>(); 
    if (obj != null) 
    { 

     var properties = obj.GetType().GetProperties(); 
     foreach (string placeHolder in placeHolders) 
     { 
      var property = properties.Where(p => p.Name == placeHolder) 
             .SingleOrDefault(); 
      if (property != null) 
      { 
       map.Add(placeHolder, property.GetValue(obj, null)); 
      } 
     } 
    } 
    return map; 
} 

РЕДАКТИРОВАТЬ: Приведенный выше пример был написан, чтобы проиллюстрировать, как LINQ, могут быть использованы. Мое предпочтение на самом деле использует вспомогательный метод для получения значений по имени. Обратите внимание, что приведенный ниже метод предполагает, что свойство существует, но может быть легко изменено для возврата null, когда свойство не существует. В моем использовании мои обращения к нему проверяются модульными тестами, поэтому я не беспокоюсь о дополнительной проверке.

public static class TypeHelper 
{ 
    public static object GetPropertyValue(object obj, string name) 
    { 
     return obj == null ? null : obj.GetType() 
             .GetProperty(name) 
             .GetValue(obj, null); 
    } 
} 
+0

К сожалению Есть 45 столбцов в этой таблице. Я предполагаю, что производительность не будет слишком большой, используя отражение здесь (не знаю много об этом). Должен ли я просто вводить поля отдельно, т.е. plcHolder.Replace («[OrderNo]», order.OrderNo)? – 2009-03-25 14:41:20

+0

Используя мой образец, вы используете только одно отражение, чтобы получить свойства и поместить их на карту. С этого момента вы будете ссылаться на них с карты по имени, чтобы получить значение. Я думаю, что я предпочел бы это решение, когда будет много столбцов и введите их вручную, если их будет только несколько. – tvanfosson

+0

Обратите внимание, что я, вероятно, сделаю что-то более простое. Моим первоначальным примером было просто продемонстрировать LINQ в сценарии. Я обновил код, который я действительно использую для этого. – tvanfosson

2

Несомненно. Тем не менее, ничто в рамках этого не поддерживает. Вам нужно будет выполнить поиск тегов, а затем использовать отражение для доступа к соответствующим свойствам в объекте Order.

Другой, более простой способ (без отражения) не будет сбрасывать ваш заказ в Hashtable ... Вот некоторые псевдокод, которые могли бы реально работать как:

var hashy = 
    (from o in Orders where o.Id = id select 
    new Dictionary<string,object>{ {"Id", o.Id}, 
    {"Name",o.Name}, /*yadda*/}).Single(); 

На данный момент, все, что вам нужно для этого нужно получить строку из вашего текстового файла и указатель в ваш хэш.

По-видимому, Linq to Sql не любит инициализаторы списка в запросах. Возможно, вы сможете обернуть это в вызове метода; Я не уверен.

Немного модификации и вы получите эту рабочую версию:

var hashy = 
(from o in Orders where o.Id = id select o).ToArray() 
.Select(o=> new Dictionary<string,object>{{"Name",o.Name}}) 
.First() 

Его не столь элегантный, потому что вы отключения вызова Linq через ToArray(), который будет тянуть обратно все заказы. В конце концов, вероятно, лучше всего просто вытащить свой заказ, заполнить необходимую информацию в хеше, а затем обработать ваш текстовый файл. Вам придется перекомпилировать, если ваша база данных изменится; опять же, это не так изящно, как моя первая попытка ...

2

Для тех, кто ищет решения, это работает для меня, чтобы получить список писем:

Dim doc = From u In db.myTable, d In db.myTable2 _ 
         Where u.UserId = d.UserId _ 
         Select u.Email 
    If doc.Count > 0 Then 
     For Each rec In doc 
      strEmailBcc += rec & "; " 
     Next 
    Else 
     MsgBox("No e-mails were found.", MsgBoxStyle.Information, "E-mail Search") 
    End IF