String.Format в запросе linq - PullRequest
3 голосов
/ 17 мая 2011

Я застрял на странной проблеме.У меня есть класс CashGameGeneralViewModel, который выглядит следующим образом

public class CashGameGeneralViewModel
{
    public string Limit { get; set; }
    public int HandsPlayed { get; set; }

    public float AmountWon { get; set; }
}

Вот метод, который должен возвращать все руки, сыгранные определенным игроком:

public List<CashGameGeneralViewModel> GetAllHands(string playerToFind)
    {
        HoldemHandContext db = new HoldemHandContext();
        int playerId = GetPlayerId(playerToFind);
        var holdemHandResult = (from phh in db.PlayersInHoldemHands
                                from hh in db.HoldemHands
                                where hh.Id == phh.HandPlayed && phh.PlayerId == playerId
                                select new CashGameGeneralViewModel()
                                           {
                                               Limit = //"some text",
                                               String.Format("{0:0.00}", hh.SBlindAmount) + "/" +
                                               String.Format("{0:0.00}", hh.BBlindAmount),
                                               HandsPlayed = db.HoldemHands.Distinct().Count(),
                                               AmountWon = 0
                                           }
                                ).ToList();

        return holdemHandResult;
    }

    public int GetPlayerId(string playerToFind)
    {
        HoldemHandContext db = new HoldemHandContext();
        int playerId = (from p in db.Players
                        where p.ScreenName == playerToFind
                        select p.Id).FirstOrDefault();

        return playerId;
    }

Проблема теперь заключается в

Limit = //"some text",
String.Format("{0:0.00}", hh.SBlindAmount) + "/" +
String.Format("{0:0.00}", hh.BBlindAmount)

часть.hh.SBlindAmount и hh.BBlindAmount являются значениями с плавающей точкой.Я хотел использовать String.Format, потому что 0.10 сокращен до 0.1 и с форматом строки я получил его, как я хочу.Но я получаю исключение, которое говорит 'The invocation of the constructor on type 'PokerRecord.View.CashGameGeneralUC' that matches the specified binding constraints threw an exception.' Line number '60' and line position '18'..Когда я удаляю string.format и вставляю какую-то "обычную" строку, все работает нормально ... Кто-нибудь знает почему?

Ответы [ 4 ]

2 голосов
/ 17 мая 2011

Я думаю, что для того, что вы пытаетесь сделать (форматировать конкретное значение с плавающей точкой в ​​строку), вам нужна перегрузка .ToString(), которая позволяет вам предоставлять поставщика формата.

Что-то вроде SmallBlind.ToString("{0:0.00}")

То, что вы, вероятно, ищете, может быть лучше всего представлено:

Limit = string.Format("{0} / {1}",
           SmallBlind.ToString("{0:0.00}"),
           BigBlind.ToString("{0:0.00}")),
//Rest of statement here...

Исходя из ошибки, которую вы получаете (у меня вчера была похожая ошибка) вот мое решение:

Limit = GetLimit(SmallBlind, BigBlind),
//Rest of Statement Here

Затем определите Get Limit со строкой. Формат:

private string GetLimit(double smallBlind, double bigBlind)
{
    return string.Format("{0} / {1}",
           smallBlind.ToString("{0:0.00}"),
           bigBlind.ToString("{0:0.00}"));
}

Я оставлю это лучшим экспертам, чем я, ПОЧЕМУ это приводит к сбою в Linq, но это должно помочь вам в этом.

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

Возможно, есть лучший способ сделать то, что я делаю, но, столкнувшись с той же проблемой, что и у вас, я решил ее так.

1 голос
/ 16 августа 2012

Длинный ответ:

Некоторые вещи плохо переводятся из методов CLR в TSQL. Хорошим примером является форматирование даты, поскольку методы .ToString (string s), .ToShort ... и т. Д. Полагаются на целый ряд специфичных для локали настроек для форматирования конечного результата. (Разделители, порядок различных частей даты, какая календарная эра используется, названия месяца / дня и т. Д.). T-SQL не поддерживает все те специфичные для локали вещи, которые поддерживаются в деталях, как .net, и не имеет других диалектов SQL СУБД. Другими словами, перевод метода .net DateTime.ToShortDateString в TSQL приведет к очень большому куску SQL, в котором будут учтены все специфичные для локали факторы форматирования, или, в качестве альтернативы, к методу, возвращающему результат, отличный от .net. эквивалент. (Что было бы еще более запутанным).

Чтобы проиллюстрировать, что при форматировании даты и времени в .net задействовано достаточное количество логики, специфичной для локали, я включил выходные данные DateTime.ToShortDateString и DateTime.ToLongDateString в паре различных настроек языка / языка для сегодняшней даты:

en-us (US English):
11/15/2010
Monday, November 15, 2010

sv-se (Swedish):
2010-11-15
den 15 november 2010

zh-cn (Chinese):
2010/11/15
2010年11月15日

ar-sa (Arabic / Saudi Arabia):
09/12/31
09/ذو الحجة/1431

th-th (Thai):
15/11/2553
15 พฤศจิกายน 2553

Да, все верно, все пять приведенных выше примеров - это одна и та же дата (15 ноября 2010 г.) с разными настройками культуры / локали. Представьте себе размер представления T-SQL всего кода форматирования даты, необходимого для этого. Вероятно, не то, что вы хотели бы поразить вашу базу данных ...:)

Итак, чтобы ответить на ваш вопрос: лучше всего делать форматирование даты и делать другие вещи, которые хорошо подходят .net, но которые нельзя перевести на T-SQL в коде .net. Либо в отдельном классе проекции, у которого есть свойство, которое выполняет форматирование, либо путем проецирования запроса L2E на типы .net, а затем выполните второй запрос L2O (linq-to-objects), который проецирует в новый тип с форматированием и т. Д. преобразования, которые вы можете захотеть сделать.

Краткий ответ:

Выполните это в два этапа - один запрос L2E, выполняющий часть, поддерживаемую L2E, и запрос L2O, выполняющий форматирование даты, и другие действия, которые лучше всего выполнять в коде .net ...

//Linq-to-entities query to get the fullname, categoryname, and date
var query = from c in db.Contacts select new { c.FullName, c.Category.CategoryName, c.DateCreated };

//Linq-to-objects query (.AsEnumerable will separate the L2E from L2O part) that call date formatting methods and other stuff that isn't supported by L2E
var r = from c in query.AsEnumerable() select new { c.FullName, c.CategoryName, ShortDate = c.DateCreated.ToString("D") };

Ответ скопирован с здесь (форум MSDN)

1 голос
/ 17 мая 2011

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

1 голос
/ 17 мая 2011

Еще один ответ, о котором я только что подумал, и то, как я, вероятно, предпочел бы это сделать. Я бы сказал, что просто сохраните эти исходные значения в ViewModel, а затем измените свойство Limit, чтобы просто создать строку на основе этих значений:

public string Limit { get { return string.Format("{0:0.00}/{1:0.00}", SmallBlind, BigBlind); } }

Edit:

Я добавлю свои аргументы в пользу того, что я предпочитаю это так - это не разрушительно. Но это может быть излишним или совершенно ненужным, если ваша ViewModel не изменится сильно или вы знаете, что вам никогда не понадобятся свойства BigBlind / SmallBlind в будущем.

...