How to return values from two different tables?

2

I'm working on an auto complete script that should search two peer tables (Courses and Packages) (unrelated) and return the merged values in a single list. The problem is that the query below is not returning any value:

[HttpGet]
public JsonResult Autocomplete(Entities db, string search)
{
    JavaScriptSerializer json = new JavaScriptSerializer();

    var query = from c in db.courses.Where(c => c.title.Contains(search))
                from p in db.packages.Where(p => p.title.Contains(search))
                select new { c, p };

    return Json(query.ToList(), JsonRequestBehavior.AllowGet);
}

But when the search is done individually the data is returned normally:

var query = from c in db.courses.Where(c => c.title.Contains(search))
            select new { c };

I need the search-related values to be returned from both tables at the same time, or that individual searches are made but merged later.

How can I resolve?

    
asked by anonymous 07.06.2016 / 20:34

3 answers

3

To return only to a list you can use the concat .

Scenario 1:

I have two entities: courses and packages , where:

  • courses has three fields ( id, title and status ) and;
  • packages has two fields ( id and title ).

You then need to normalize by putting the same amount of fields in the packages entity and also observe the field type so that it has no conversion errors. The type bool? has been set because the status field of courses is of this type; How to get the field type: é só olhar na entidade mapeado o seu tipo

using (MyDbContext db = new MyDbContext())
{

    var courses = db.Cours.Select(c => new
    {
        c.Id, 
        c.Title, 
        c.Status
    });

    var packages = db.Packages.Select(c => new 
    {
        c.Id, 
        c.Title, 
        Status = new bool?()
    });

    var js = courses.Concat(packages);
    var items = js.ToList();

}

Scenario 2:

I want to get the same both entities fields and they are equal, for example id and name , as would be:

using (MyDbContext db = new MyDbContext())
{

    var courses = db.Cours.Select(c => new
    {
        c.Id, 
        c.Title
    });

    var packages = db.Packages.Select(c => new 
    {
        c.Id, 
        c.Title
    });

    var js = courses.Concat(packages);
    var items = js.ToList();

}

Note: The two scenarios that resolve is the SQL part of the database, and there is no downtime.

In your code :

[HttpGet]
public JsonResult Autocomplete(Entities db, string search)
{
    JavaScriptSerializer json = new JavaScriptSerializer();

    var courses = db.Courses.Select(c => new
    {
        c.Id,
        c.Title
    });

    var packages = db.Packages.Select(c => new
    {
        c.Id,
        c.Title
    });

    var js = courses.Concat(packages);

    return Json(js.Where(c => c.Title
                  .Contains(search))
                  .ToList(), JsonRequestBehavior.AllowGet);
}

Microsoft Site Example:

Concatenate Two Sequences

IQueryable<String> custQuery =
    (from cust in db.Customers
    select cust.Phone)
    .Concat
    (from cust in db.Customers
    select cust.Fax)
    .Concat
    (from emp in db.Employees
    select emp.HomePhone);

foreach (var custData in custQuery)
{
    Console.WriteLine(custData);
}

This example illustrates very well that field types must be of the same type regardless of the field name (although aliasing can be done for good code reading) and in the same order. >

    
13.06.2016 / 19:23
3

There are a few ways you can do this, one of which is to return the results through a dynamic list.

It would look something like this:

[HttpGet]
public JsonResult Autocomplete(Entities db, string search)
{
    JavaScriptSerializer json = new JavaScriptSerializer();

    return Json(new { 
                  couses = db.courses.Where(c => c.title.Contains(search)).ToList(),
                  packages = db.packages.Where(p => p.title.Contains(search)).ToList()
        }, JsonRequestBehavior.AllowGet);
}

So you'll get a return like this:

{
  "couses": [
    {
      //Lista de courses
    }
  ],
  "packages": [
    {
      //Lista de Packages
    }
  ],
}

Or you can also create a ViewModel , leaving everything typed and organized.

But if one table is unrelated to the other, I would not try to include everything in the same select , otherwise it would become a mess and difficult to maintain.

    
09.06.2016 / 23:08
1

You can use SelectMany to merge its values, just to an issue this would be for a case where db.packages.Where(p => p.title.Contains(search) is compared to a db.courses.Where(c => c.title variable, but since you did not pass the template it would be difficult to create a better solution, but in the way that I think it will solve.

    var query = db.courses.Where(c => c.title.Contains(search)
      .SelectMany(C => db.packages.Where(p => p.title.Contains(search).DefaultIfEmpty()
      , (n, a) => new
            { n, a }
      );

View reference .

    
09.06.2016 / 22:51