How to join tables using linq and entity framework - entity-framework

In the code given below i want to join all the three table i get the data by joining the table but while displaying the data only the data of CK_Model is displayed. Please help
public List<CK_Model> GetDetails()
{
try
{
using (var entities = new MobileStore2020Entities())
{
var details = from a in entities.CK_Model
join b in entities.CK_Brand
on a.BrandID equals b.BrandID
join c in entities.CK_Stock
on a.ModelID equals c.ModelID
select new
{
ModelID = a.ModelID,
ModelName = a.ModelName
};
return details.ToList();
Thank You.

If I understand correctly you want to return data from all 3 tables by accessing them through your context. If you want to do this you have change your method's return type. For example create a new class with all 3 item types
public class DetailsItemType
{
public CK_Model Model{ get; set; }
public CK_Brand Brand { get; set; }
public CK_Stock Stock { get; set; }
}
Then change your method's return type to DetailsItemType and you'll have something like the following
public List<DetailsItemType> GetDetails()
{
using (var entities = new MobileStore2020Entities())
{
var details = from a in entities.CK_Model
join b in entities.CK_Brand
on a.BrandID equals b.BrandID
join c in entities.CK_Stock
on a.ModelID equals c.ModelID
select new DetailsItemType
{
Model= a,
Brand = b,
Stock = c
};
return details.ToList();
}
}
Now every time you call GetDetails() you can access all 3 tables. For example
var details = GetDetails();
var model = details.Model;
var brand = details.Brand;
var stock = details.Brand;

Related

Clear DataGridView datasource linked to Entity Framework

I'm new to Entity Framework, I have a DataGridView connected to Entity Framework as it shown below
dgvDebit.DataSource = (from daily in accountingEntities.DailyAccounts
join voucherdetails in accountingEntities.VoucherDetails on daily.DailyId equals voucherdetails.DailyId
where voucherdetails.VoucherId == keyvalue
group voucherdetails by daily.DailyName into dgroup
select new
{
DailyName = dgroup.Key,
SumOfDebit = dgroup.Sum(s => s.Debit)
}).ToList();
My question is: I want to clear DataGridView datasource but every thing I did has failed - please any help here?
OK, so you want to bind to an empty list of the type that you have.
Step 1: define a .NET type for your query result return type:
public class ResultDTO
{
public string DailyName { get; set; }
public decimal SumOfDebit { get; set; }
}
Step 2: change your "normal" query to:
dgvDebit.DataSource = (from daily in accountingEntities.DailyAccounts
join voucherdetails in accountingEntities.VoucherDetails on daily.DailyId equals voucherdetails.DailyId
where voucherdetails.VoucherId == keyvalue
group voucherdetails by daily.DailyName into dgroup
select new ResultDTO
{
DailyName = dgroup.Key,
SumOfDebit = dgroup.Sum(s => s.Debit)
}).ToList();
Step 3: if you want to "clear" the DataGridView, but retain the columns, you can now use:
dgvDebit.DataSource = new List<ResultDTO>();

Context SqlQuery<>() without detailing all columns

Let's say I have a Person entity with 3 columns:
public PERSON {
public int OID { get; set; }
public string NAME { get; set; }
public string SURNAME { get; set; }
}
I want to query it with raw SQL but without specifying all columns so I write:
var query = "select NAME, SURNAME from PERSON";
var list = context.SqlQuery<PERSON>(query).ToList();
But it throws Exception:
System.Data.Entity.Core.EntityCommandExecutionException : The data reader is incompatible with the specified '...'. A member of the type, 'OID', does not have a corresponding column in the data reader with the same name.
So it seems like it tries to map all columns, and, if some are missing, it throws.
Is there a way to make it ignore columns that are not present in raw SQL query and map just the columns that are accessible?
The reason is, I have a lot of columns for some entities and sometimes I just want to query partial columns. I don't want to create new class with just the necessary columns for each query.
I can think of 3 options off the top of my head that could work for you.
Option 1: Rewrite your queries and use a standard Linq query:
var persons = from p in context.Persons
select new PERSON
{
NAME = p.NAME,
SURNAME = p.SURNAME
};
Option 2: Return a dummy value for columns you don't need
var query = "select 0 AS OID, NAME, SURNAME from PERSON";
var list = context.SqlQuery<AlmostPERSON>(query).ToList();
Option 3: Create your own intermediate classes with the columns you need from the database:
public class AlmostPERSON
{
public string NAME { get; set; }
public string SURNAME { get; set; }
}
var query = "select NAME, SURNAME from PERSON";
var list = context.SqlQuery<AlmostPERSON>(query).ToList();
You could even project this intermediate class onto your standard entity like this:
var list = context.SqlQuery<AlmostPERSON>(query)
.Select(ap => new PERSON
{
NAME = ap.NAME,
SURNAME = ap.SURNAME
})
.ToList();
Found one more possible solution: using ADO.NET IDataReader with AutoMapper
public List<T> ExecuteFor<T>(string sql)
{
using (_connection = new OracleConnection(_connectionString))
{
_connection.Open();
using (var command = new OracleCommand(sql, _connection))
{
using (OracleDataReader reader = command.ExecuteReader())
{
Mapper.CreateMap<IDataReader, List<T>>();
return Mapper.Map<IDataReader, List<T>>(reader);
}
}
}
}

IQueryable.Select to a List type sub POCO

I have an Entity Framework model in which there is a "Customers" and a "CustomerPhones" table. A customer can have multiple phone numbers so the "Customer" entity has a collection of "Phone". I can query the model with no problem :
using (CustomerEntities context = new CustomerEntities())
{
Customer customer = context.Customers.FirstOrDefault();
CustomerPhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
The model is too complex for what I need to do (even though my example is basic) so I'm trying to boil it down to simpler POCOs. Here are the 2 simple classes :
public class SimplePhone
{
public int Id { get; set; }
public string Number { get; set; }
}
public class SimpleCustomer
{
public int Id { get; set; }
public string Name { get; set; }
//Phones is a list because a single Customer can have multiple phone numbers
public List<SimplePhone> Phones { get; set; }
}
I can populate the simple properties of the object using the "Select" method of "IQueryable" :
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
}
);
SimpleCustomer customer = customers.FirstOrDefault();
MessageBox.Show(customer.Name);
}
So my question is pretty simple : how can I populate the "Phones" property which is a list?
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
Phones = ///????
}
);
SimpleCustomer customer = customers.FirstOrDefault();
SimplePhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
Let me know if I'm unclear and/or you need more details.
Thanks!
I'm not sure if there isn't something more to your question, but as far as I understand, you can just call ToList and it will be materialized as a list:
IQueryable<SimpleCustomer> customers =
context.Customers.Select(c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name,
Phones = c.Phones.Select(p => new SimplePhone
{
Id = p.Id, // Unless you want the custom Id, i.e. c.Id
Number = p.Number
}).ToList();
});

how to read data from junction table code first approach

how can I retrieve data from junction table in Code first approach.i know i can add data like this.
Movie.Tag.Add(item)
but want to know how to get back those data in the junction table
This gives you all rows in the junction table - each row is represented as an anonymous object with the two Ids of the row as properties:
var junctionTableDataList = (from m in context.Movies
from t in m.Tags
select new
{
MovieId = m.MovieId,
TagId = t.TagId
}).ToList();
You can add a where clause before the select if you want to limit the result to a specific or a few movies.
Edit
The same with extension methods and lambda expressions would look like this:
var junctionTableDataList = context.Movies
.SelectMany(m => m.Tags.Select(t => new
{
MovieId = m.MovieId,
TagId = t.TagId
}))
.ToList();
Edit 2
If you want return the data from a method you can create a litte helper type and return a list of those "named" objects instead of anonymous objects:
public class JunctionData
{
public int MovieId { get; set; }
public int TagId { get; set; }
}
List<JunctionData> junctionTableDataList
= (from m in context.Movies
from t in m.Tags
select new JunctionData
{
MovieId = m.MovieId,
TagId = t.TagId
}).ToList();
Or ...Select(t => new JunctionData... for the extension method syntax.

Problems with selecting 2 column values in Linq to Entity

Hi I am trying to select the values of two columns which are second driver and price but I am getting error: Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists (are you missing a cast?)
Below is the code:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select new{ p.SecondDriver,
p.SecondDriverPrice};
return SecondDriver;
}
Any help or suggestions will be appreciated thnx
You cannot use projection when you expect IQueryable<Event> where Event is your mapped type. You must either select Event :
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select p;
Or you must create new type and project data to a new type:
public class EventDto
{
public Driver SecondDriver { get; set; }
public Price SecondDriverPrice { get; set; }
}
and redefine your method:
public IQueryable<EventDto> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<EventDto> SecondDriver = from p in entity.Events
where p.ID == eventID
select new EventDto
{
SecondDriver = p.SecondDriver,
SecondDriverPrice = p.SecondDriverPrice
};
return SecondDriver;
}
You cannot return anonymous objects. Try like this:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
var seconDriver =
from p in entity.Events
where p.ID == eventID;
select p;
return secondDriver;
}