web-dev-qa-db-fra.com

Conversion de date/heure en chaîne mise en forme dans une requête LINQ to SQL

Je sais que LINQ to SQL ne convertit pas DateTime en string puisqu'il n'y a pas de ToString() en SQL. Mais comment puis-je convertir la DateTime en une chaîne formatée?

C'est la ligne dans la requête suivante qui a besoin d'aide:

StartDate = string.Format("{0:dd.MM.yy}", p.StartDate)

La requête entière:

var offer = (from p in dc.CustomerOffer
             join q in dc.OffersInBranch
             on p.ID equals q.OfferID
             where q.BranchID == singleLoc.LocationID
             let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
             orderby value descending
             select new Offer()
             {
                 Title = p.OfferTitle,
                 Description = p.Description,
                 BestOffer = value,
                 ID = p.ID,
                 LocationID = q.BranchID,
                 LocationName = q.CustomerBranch.BranchName,
                 OriginalPrice = SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                 NewPrice = SqlFunctions.StringConvert((decimal)p.NewPrice),
                 StartDate = string.Format("{0:dd.MM.yy}", p.StartDate)
             }).First();

Je reçois le message d'erreur suivant:

LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.

19
kandroid

EDIT: Maintenant que je comprends la question, je lui donne un autre coup :)

var offer = (from p in dc.CustomerOffer
                     join q in dc.OffersInBranch
                         on p.ID equals q.OfferID
                     where q.BranchID == singleLoc.LocationID
                     let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                     orderby value descending
                     select new
                     {
                         Title = p.OfferTitle,
                         Description = p.Description,
                         BestOffer=value,
                         ID=p.ID,
                         LocationID=q.BranchID,
                         LocationName=q.CustomerBranch.BranchName,
                         OriginalPrice=SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                         NewPrice=SqlFunctions.StringConvert((decimal)p.NewPrice),
                         StartDate=p.StartDate

                     })
                     .ToList()
                     .Select(x => new Offer()
                     {
                         Title = x.OfferTitle,
                         Description = x.Description,
                         BestOffer=value,
                         ID=x.ID,
                         LocationID=x.BranchID,
                         LocationName=x.CustomerBranch.BranchName,
                         OriginalPrice=x.OriginalPrice,
                         NewPrice=x.NewPrice,
                         StartDate=x.StartDate.ToString("dd.MM.yy")
                     }).First();

Je sais que c'est un peu long, mais c'est le problème avec Linq To SQL.

Lorsque vous utilisez linq, l'appel à la base de données n'est exécuté que lorsque vous utilisez un élément tel que ToList () ou First () qui génère des objets. Une fois que cet appel SQL est exécuté par le premier appel .First (), vous travaillez maintenant avec des types .NET et pouvez utiliser les commandes DateTime.

13
mccow002

Une autre option utilise SqlFunctions.DateName, votre code sera comme ceci:

var offer = (from p in dc.CustomerOffer
                 join q in dc.OffersInBranch
                     on p.ID equals q.OfferID
                 where q.BranchID == singleLoc.LocationID
                 let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                 orderby value descending
                 select new
                 {
                     Title = p.OfferTitle,
                     Description = p.Description,
                     BestOffer=value,
                     ID=p.ID,
                     LocationID=q.BranchID,
                     LocationName=q.CustomerBranch.BranchName,
                     OriginalPrice=SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                     NewPrice=SqlFunctions.StringConvert((decimal)p.NewPrice),
                     StartDate= SqlFunctions.DateName("day",p.StartDate) + "/" + SqlFunctions.DateName("month",p.StartDate) + "/" +  SqlFunctions.DateName("year",p.StartDate)

                 })

Je l'ai trouvé utile si vous ne voulez pas ajouter un nouveau bloc de sélection supplémentaire.

25
Alberto Montellano

J'ai fini par utiliser la fonction SQL FORMAT; voici une version simplifiée de cette implémentation:

https://weblogs.asp.net/ricardoperes/registering-sql-server-built-in-functions-to-entity-framework-code-first

Vous devez d’abord définir la fonction dans EF:

public class FormatFunctionConvention : IStoreModelConvention<EdmModel>
{
    public void Apply(EdmModel item, DbModel model)
    {
        var payload = new EdmFunctionPayload
        {
            StoreFunctionName = "FORMAT",
            Parameters = new[] {
                FunctionParameter.Create("value", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.DateTime), ParameterMode.In),
                FunctionParameter.Create("format", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), ParameterMode.In)
            },
            ReturnParameters = new[] {
                FunctionParameter.Create("result", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), ParameterMode.ReturnValue)
            },
            Schema = "dbo",
            IsBuiltIn = true
        };

        item.AddItem(EdmFunction.Create("FORMAT", "CodeFirstDatabaseSchema", item.DataSpace, payload, null));
    }
}

Puis définissez-le en tant que méthodes C #:

public static class SqlFunctions
{
    [DbFunction("CodeFirstDatabaseSchema", "FORMAT")]
    public static String Format(this DateTime value, string format)
    {
        return value.ToString(format);
    }

    [DbFunction("CodeFirstDatabaseSchema", "FORMAT")]
    public static String Format(this DateTime? value, string format)
    {
        return value?.ToString(format);
    }
}

Enregistrez-le dans votre DbContext:

public class SqlDb : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Add(new FormatFunctionConvention());
    }
}

Et enfin, vous pouvez l'appeler comme suit:

var x = db.MyItems.Select(i => new { FormattedDate = SqlFunctions.Format(i.MyDate, "MM/dd/yyyy") }).ToArray();
0
John

s'il s'agit d'une date et heure, vous devez utiliser la fonction .ToShortDateString(). Mais vous devez également le déclarer AsEnumerable ().

var offer = (from p in dc.CustomerOffer.AsEnumerable()
                 join q in dc.OffersInBranch
                     on p.ID equals q.OfferID
                 where q.BranchID == singleLoc.LocationID
                 let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                 orderby value descending
                 select new
                 {
                     Title = p.OfferTitle,
                     Description = p.Description,
                     BestOffer=value,
                     ID=p.ID,
                     LocationID=q.BranchID,
                     LocationName=q.CustomerBranch.BranchName,
                     OriginalPrice=SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                     NewPrice=SqlFunctions.StringConvert((decimal)p.NewPrice),
                     StartDate=p.StartDate

                 })
                 .ToList()
                 .Select(x => new Offer()
                 {
                     Title = x.OfferTitle,
                     Description = x.Description,
                     BestOffer=value,
                     ID=x.ID,
                     LocationID=x.BranchID,
                     LocationName=x.CustomerBranch.BranchName,
                     OriginalPrice=x.OriginalPrice,
                     NewPrice=x.NewPrice,
                     StartDate=x.StartDate.ToShortDateString()
                 }).First();
0
user1760784

C'est ce que nous avons fait, nous avons ajouté une nouvelle fonction à la classe et nous interrogeons la date comme d'habitude dans la requête:

[ComplexType]
public class Offer
{    
    public DateTime StartDate 
    {
        get;
        set;
    }

   public String Title
   {
       get;
       set;
   }

   /*Other fields*/      
   .
   .
   .


    public string FormattedDate(string format)
    {
        return Date.ToString(format);
    }
}



var offer = (from p in dc.CustomerOffer
         join q in dc.OffersInBranch
         on p.ID equals q.OfferID
         where q.BranchID == singleLoc.LocationID
         let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
         orderby value descending
         select new Offer()
         {
             Title = p.OfferTitle,
             Description = p.Description,
             BestOffer = value,
             ID = p.ID,
             LocationID = q.BranchID,
             LocationName = q.CustomerBranch.BranchName,
             OriginalPrice = SqlFunctions.StringConvert((decimal)p.OriginalPrice),
             NewPrice = SqlFunctions.StringConvert((decimal)p.NewPrice),
             StartDate = p.StartDate
         }).First();

Ensuite, vous pouvez simplement appeler le champ FormattedDate en passant le format souhaité.

edit1.Text = offer.FormattedDate("dd.MM.yy");

Ou peut peut définir comme un champ avec seulement le getter:

    public string FormattedDate
                {
                   get { return Date.ToString("dd.MM.yy") };
                }

 edit1.Text = offer.FormattedDate;

Si votre classe est une entité, vous devez déclarer un nouveau partiel de cette classe et ajouter le champ.

J'espère que cela aidera quelqu'un.

0
Gabrielkdc