Как выполнить Linq select new с datetime в SQL 2008 - PullRequest
1 голос
/ 12 мая 2010

В нашем коде C # я недавно изменил строку из запроса linq-to-sql select new следующим образом:

OrderDate = (p.OrderDate.HasValue ? 
    p.OrderDate.Value.Year.ToString() + "-" + 
    p.OrderDate.Value.Month.ToString() + "-" + 
    p.OrderDate.Value.Day.ToString() : "")

Кому:

OrderDate = (p.OrderDate.HasValue ? 
    p.OrderDate.Value.ToString("yyyy-mm-dd") : "")

Изменение делает линию меньше и чище. Он также отлично работает с нашей базой данных SQL 2008 в нашей среде разработки. Однако, когда код был развернут в нашей производственной среде, использующей SQL 2005, я получил исключение: Nullable Type must have a value. Для дальнейшего анализа я скопировал (p.OrderDate.HasValue ? p.OrderDate.Value.ToString("yyyy-mm-dd") : "") в строку (вне оператора Linq), и у меня не было никаких проблем, так что это только вызывает проблему внутри моего Linq. Эта проблема как-то связана с SQL 2005, использующим другие форматы даты, чем с SQL 2008?

Вот еще Линк:

var FilteredOrders = [linq-to-sql query].AsEnumerable().ToList<Order>();

                dt = FilteredOrders.Where(x => x != null).Select(p =>
                new
                {
                    Order = p.OrderId,
                    link = "/order/" + p.OrderId.ToString(),
                    StudentId = (p.PersonId.HasValue ? p.PersonId.Value : 0),
                    FirstName = p.IdentifierAccount.Person.FirstName,
                    LastName = p.IdentifierAccount.Person.LastName,
                    DeliverBy = p.DeliverBy,
                    OrderDate = p.OrderDate.HasValue ? 
                        p.OrderDate.Value.Date.ToString("yyyy-mm-dd") : 
                        ""
                }).ToDataTable();

Это выбор из списка объектов Order. Список FilteredOrders взят из другого запроса linq-to-sql, и я вызываю его .AsEnumerable перед тем, как передать его этому конкретному запросу select new.

Выполнение этого в обычном коде работает нормально:

if (o.OrderDate.HasValue)
    tempString += " " + o.OrderDate.Value.Date.ToString("yyyy-mm-dd");

Вот трассировка стека от ошибки. Это часть большой системы в школе для получения заказов на стенограммы из БД для отображения на экране.

Line 46:   
Line 47:            dt = FilteredOrders.Where(x => x != null).Select(p =>  
Line 48:            new  
Line 49:                     { 
Line 50:                         Order = p.OrderId,


Stack Trace:

[InvalidOperationException: Nullable object must have a value.]    System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) +51    System.Nullable`1.get_Value() +1373881 Aqueduct.Platform.Web.packages.finance_carttranscriptorder_default.<PopulateSearchResultsGrid>b__1(CartTranscriptOrder p) in D:\Repositories\aqueduct\Aqueduct.Platform.Web\trunk\packages\finance\carttranscriptorder\default.aspx.cs:48 System.Linq.WhereSelectListIterator`2.MoveNext()
+107    System.Linq.Buffer`1..ctor(IEnumerable`1 source) +434    System.Linq.<GetEnumerator>d__0.MoveNext()
+108    Aqueduct.Core.Data.ObjectShredder`1.Shred(IEnumerable`1 source, DataTable table, Nullable`1 options) in D:\Repositories\aqueduct\Aqueduct.Core\trunk\Data\LinqExtensions.cs:116 Aqueduct.Core.Data.LinqExtensions.ToDataTable(IEnumerable`1 source) in D:\Repositories\aqueduct\Aqueduct.Core\trunk\Data\LinqExtensions.cs:49 Aqueduct.Platform.Web.packages.finance_carttranscriptorder_default.PopulateSearchResultsGrid(List`1 FilteredOrders) in D:\Repositories\aqueduct\Aqueduct.Platform.Web\trunk\packages\finance\carttranscriptorder\default.aspx.cs:47 Aqueduct.Platform.Web.packages.finance_carttranscriptorder_default.RunFilter() in D:\Repositories\aqueduct\Aqueduct.Platform.Web\trunk\packages\finance\carttranscriptorder\default.aspx.cs:101 Aqueduct.Platform.Web.packages.finance_carttranscriptorder_default.Page_Load(Object sender, EventArgs e) in D:\Repositories\aqueduct\Aqueduct.Platform.Web\trunk\packages\finance\carttranscriptorder\default.aspx.cs:22 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
+14    System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35    System.Web.UI.Control.OnLoad(EventArgs e) +99    System.Web.UI.Control.LoadRecursive()
+50    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

Ответы [ 3 ]

4 голосов
/ 12 мая 2010

Я подозреваю, что он пытается конвертировать код в SQL. Если это всего лишь проекционная сторона, я предлагаю вам выполнить простую проекцию на биты данных, которые вам нужны в бите LINQ-to-SQL, а затем использовать AsEnumerable, чтобы заставить остальную часть запроса выполняться в .NET сам. В этот момент вы можете делать такие вещи с гораздо большей свободой. Так что в этом случае у вас будет что-то вроде:

var query = from ...
            where ...
            select new { p.OrderData, p.SomeOtherFields };

var transformed = query.AsEnumerable()
                       .Select(p => new {
   OrderDate = (p.OrderDate.HasValue ? p.OrderDate.Value.ToString("yyyy-mm-dd") 
                                     : ""),
   ... });
1 голос
/ 13 мая 2010

Когда вы делаете это в Linq to SQL

OrderDate = (p.OrderDate.HasValue ? 
    p.OrderDate.Value.ToString("yyyy-mm-dd") : "")

На самом деле он оценивает обе стороны дела, но возвращает только «истинный» случай. Так что просто сделайте что-то подобное, и это позволит избежать обнуления, но все равно даст вам правильный результат.

OrderDate = (p.OrderDate.HasValue ? 
    p.OrderDate.GetValueOrDefault(DateTime.Now).ToString("yyyy-mm-dd") : "")
0 голосов
/ 12 мая 2010

Итак, просто для подтверждения, FilteredResults выглядит примерно так:

FilteredResults = [query].AsEnumerable()

Правильно?

Если это так, то единственный вариант, который я вижу, это если OrderIDнулевой.Это обнуляемый тип?Все другие (возможно) обнуляемые свойства, кажется, имеют HasValue проверку вокруг них или не используются вообще (например, DeliverBy), поэтому я не вижу никаких других вариантов.

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

В качестве отступления, нет необходимости идти после Date свойство OrderDate.Value, поскольку функция ToString() в DateTime идеально подходит для форматирования дат без компонента времени.

...