1

I have WebAPI controller to generate xml from table data

here is code

  public class XMLController : ApiController
{
    private trackingappEntities db = new trackingappEntities();
    [HttpGet]
    public HttpResponseMessage Index()
    {
        var xdoc = new XDocument(
            new XElement("data",
                db.TimeTables.Select(w =>
                    new XElement("worker",
                        new XAttribute("id", w.INN),
                        new XElement("start", w.StartDay),
                        new XElement("pause", w.StartPause),
                        new XElement("continue", w.EndPause),
                        new XElement("end", w.EndDay)
                    )
                )
            )
        );

        return new HttpResponseMessage() { Content = new StringContent(xdoc.ToString(), Encoding.UTF8, "application/xml") };
    }
}

Here is TimeTable class

 public partial class TimeTable
{
    public int Id { get; set; }
    public string Company { get; set; }
    public string INN { get; set; }
    public string StartDay { get; set; }
    public string StartPause { get; set; }
    public string EndDay { get; set; }
    public string EndPause { get; set; }
}

But when I send request, I have this response

Only parameterless constructors and initializers are supported in LINQ to Entities.

How I can fix this?

mark_spencer
  • 393
  • 4
  • 17
  • One of your entities has a constuctor with a parameter in it, and you didn't create an empty constructor for it – johnny 5 Aug 15 '17 at 04:32
  • `XElement` & `XAttribute` methods are not intended to use with LINQ to Entities (they're work with LINQ to Objects). Try to materialize the `IQueryable` first (using `AsEnumerable` or `ToList`). – Tetsuya Yamamoto Aug 15 '17 at 04:32
  • So i need to `new XDocument` To List first? @TetsuyaYamamoto – mark_spencer Aug 15 '17 at 04:33
  • 1
    @mark_spencer `db.TimeTables.AsEnumerable().Select(...)` or `db.TimeTables.ToList().Select(...)` can be enough to materalize query results into memory (those XML methods obviously have no SQL equivalent). – Tetsuya Yamamoto Aug 15 '17 at 04:35

1 Answers1

5

LINQ works by inspecting the code of your function calls, rather than simply their result.

In your case, the likely solution will just be to call AsEnumerable to tell LINQ to populate each record from SQL, before calling the constructor.

var timeTables = db.TimeTables
    /*
     * Select is optional; this would improve performance for a table with many 
     * extra properties, but would have little-to-no relevant impacts if you're
     * already using them all. Similar to a SELECT * versus selecting individual
     * columns.
     */
    .Select(c => new {
        c.INN,
        c.StartDay,
        c.StartPause,
        c.EndPause,
        c.EndDay
    })
    .AsEnumerable(); // or ...await ToListAsync();

var xdoc = new XDocument(
        new XElement("data",
            timeTables.Select(w =>
                new XElement("worker",
                    new XAttribute("id", w.INN),
                    new XElement("start", w.StartDay),
                    new XElement("pause", w.StartPause),
                    new XElement("continue", w.EndPause),
                    new XElement("end", w.EndDay)
                )
            )
        )
    );

Otherwise, you can imagine LINQ trying to essentially send the logic for generating an XElement directly to SQL. Since SQL wouldn't understand the logic involved in that process, LINQ throws.

In this example, the Select call builds an anonymous type. Because it's guaranteed to have no additional logic performed in the constructor, LINQ is able to simply select those values, and populate them C#-side.

Matthew Haugen
  • 12,916
  • 5
  • 38
  • 54