I want to merge result of two SQL select statements into one.
Here is sample :
// class
public class _Product
{
public long ProductId { get; set; }
public string Description { get; set; }
}
public class _Company
{
public long CompanyId { get; set; }
public int posotion{ get; set; }
}
// C# entity
void runQyery()
{
string MultiQuery = "select ProductId, Description from product;"+
" select CompanyId, posotion from Company;";
_Product objPro = new _Product();
_Company objCom = new _Company();
// Is this right? What should I do now?
var result = _entities.Database.ExecuteSqlCommand(MultiQuery);
objPro = ...
objCom = ...
}
How can I finish my code? Is there any way to read some select on one trying?
Thanks for your attention
Related
Im trying to write in linq something which is easy (for me) in SQL. Any idea how to do something like this:
select Items.IdItem,
Items.Name,
count(1) as Quantity,
SUM(IF(State.IdStatus=1,1,0)) as Availible
from Items
inner join State
on Items.IdItem=State.IdItem
group by Items.IdItem
I wrote something like that:
var result = from items in _context.Items
join state in _context.State on items.IdItem equals State.IdItem
group items by { items.IdItem, items.Name } into g
select new { Name= g.Key.Name, IdItem=g.Key,IdItem, Quantity=g.Count(), Availible= ???? }
Any tips?
Provided you have set your relations in the database and navigational properties in your model (which is done by generators), then in Linq you seldom need joins (for tables that don't have a direct relation).
Second, you are not really after Sum() here, are you. Looking at your sum function and field name, it more looks like you are after "Is Available" check.
var result = from i in _context.Items
group i by i.IdItem into g
select new {
IdItem = g.Key,
Name = g.First().Name,
Quantity = g.Count(),
Available = g.Any(it => it.State.IdStatus == 1)
};
EDIT: if your Sum was intentional, then you can replace the Available part by (it is a bit, right?):
Available = g.Sum(it => it.State.IdStatus)
EDIT: This one is based on your data/model and SQL at top:
var result = from i in _context.Items
select new
{
i.IdItem,
i.Name,
Quantity = i.States.Count(),
Available = i.States.Count(x => x.IdStatus == 1)
};
Sample code and results:
string defaultConString = #"server=.\SQLExpress;Database=SampleDb;Trusted_Connection=yes;";
void Main()
{
var _context = new MyContext(defaultConString);
var result = from i in _context.Items
select new
{
i.IdItem,
i.Name,
Quantity = i.States.Count(),
Available = i.States.Count(x => x.IdStatus == 1)
};
result.Dump(); // linqPad
}
public class MyContext : DbContext
{
public MyContext(string connectionString)
: base(connectionString)
{ }
public DbSet<Item> Items { get; set; }
public DbSet<State> States { get; set; }
}
[Table("Items")]
public partial class Item
{
public Item()
{
this.States = new List<State>();
OnCreated();
}
[Key]
public virtual int IdItem { get; set; }
public virtual string Name { get; set; }
public virtual System.DateTime ImportDate { get; set; }
public virtual System.DateTime ReturnDate { get; set; }
public virtual IList<State> States { get; set; }
partial void OnCreated();
}
[Table("States")]
public partial class State
{
public State()
{
OnCreated();
}
[Key]
public virtual int IdState { get; set; }
public virtual string SmId { get; set; }
public virtual string Number { get; set; }
public virtual int IdItem { get; set; }
public virtual int IdStatus { get; set; }
public virtual Item Item { get; set; }
partial void OnCreated();
}
Result:
IdItem Name Quantity Available
1 Test01 3 2
2 Test02 2 1
3 Test03 1 0
I am trying to get away from the Entity Framework since I have to support HANA Databases aside from SQL server Databases in our solution.
I am doing some research with dapper so I created a quick test environment with some fictitious scenario.
I have the following POCOs that resemble my Database schema (I have more but I limited to showing these for simplicity):
public class Adopter
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public State State { get; set; }
public int StateId { get; set; }
public string Zip { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public IEnumerable<Pet> Pets { get; set; }
}
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public string Abreviation { get; set; }
}
public class Pet
{
public int Id { get; set; }
public string IdTag { get; set; }
public string Name { get; set; }
public DateTime AdmitionDate { get; set; }
public Status Status { get; set; }
public int StatusId { get; set; }
public string Notes { get; set; }
public DateTime AdoptionDate { get; set; }
public bool IsAdopted { get; set; }
public int? AdopterId { get; set; }
public int Age { get; set; }
public decimal Weight { get; set; }
public string Color { get; set; }
public Breed Breed { get; set; }
public int BreedId { get; set; }
public Gender Gender { get; set; }
public int GenderId { get; set; }
public IEnumerable<PetImage> PetImages { get; set; }
}
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Gender
{
public int Id { get; set; }
public string Name { get; set; }
}
I am using the following in a repository to return a list of all the adopters:
using (SqlConnection connection = new SqlConnection(_connectionString))
{
var adopters = connection.Query<Adopter>("SELECT a.* FROM Adopters a");
foreach (var adopter in adopters)
{
adopter.State = connection.QueryFirst<State>("Select s.* FROM States s WHERE s.Id = #Id", new { Id = adopter.StateId });
adopter.Pets = connection.Query<Pet>("Select p.* FROM Pets p WHERE p.AdopterId = #Id", new { Id = adopter.Id });
foreach (var pet in adopter.Pets)
{
pet.Status = connection.QueryFirst<Status>("Select s.* FROM Status s WHERE s.Id = #Id", new { Id = pet.StatusId });
pet.Gender = connection.QueryFirst<Gender>("Select g.* FROM Genders g WHERE g.Id = #Id", new { Id = pet.GenderId });
}
}
return adopters;
}
As you can see, I am retrieving the data for each POCO individually based on the previous one and doing the Joins manually in code.
Is this the right way of doing it or should I be doing a big query with multiple joins and mapping the result somehow thru dapper and LINQ?
A possible improvement to your actual solution is through the use of QueryMultiple extension like this:
using (SqlConnection connection = new SqlConnection(_connectionString))
{
string query = #"SELECT * FROM Adopters;
SELECT * FROM States;
SELECT * FROM Pets;
SELECT * FROM Status;
SELECT * FROM Genders;";
using (var multi = connection.QueryMultiple(query, null))
{
var adopters = multi.Read<Adopter>();
var states = multi.Read<State>();
var pets = multi.Read<Pet>();
var statuses = multi.Read<Status>();
var genders = multi.Read<Gender>();
foreach (Adopter adp in adopters)
{
adp.State = states.FirstOrDefault(x => x.Id == adp.StateID);
adp.Pets = pets.Where(x => x.IsAdopted &&
x.AdopterID.HasValue &&
x.AdopterID.Value == adp.AdopterID)
.ToList();
foreach(Pet pet in adp.Pets)
{
pet.Status = statuses.FirstOrDefault(x => x.Id == pet.StatusID);
pet.Gender = genders.FirstOrDefault(x => x.Id == pet.GenderID);
}
}
}
}
The benefit here is that you reach the database just one time and then process everything in memory.
However this could be a performance hit and a memory bottleneck if you have a really big data to retrieve, (and from a remote location). Better to look closely at this approach and try also some kind of Async processing and/or pagination if possible.
I don't like to be negative, but... don't do this! Don't even think like this. You want to dump EF, but you're walking into the trap by wanting to emulate EF. The bridge between your app and your DB is not something to be built once for all time, for every conceivable purpose. Concretely, you shouldn't really ever bring back a whole table, and certainly not to then loop on every row and emit more queries. You may feel unjustly criticised, you were just testing the tools ! If so, perhaps tell us what aspect of the tool your examining, and we'll focus in on that.
Dapper or QueryFirst greatly simplify running queries, and consuming the results, so bring back just what you need, just when you need it. Then denormalize a little, for the specific job in hand. Why are there no joins in your queries? RDBMSs are amazing, and amazingly good at doing joins. If you're joining data outside the DB, crazy is the only word, even if Linq gives you a super (sql-like) syntax for doing it. The unthinking assumption that 1 table corresponds to 1 class is the start of a lot of problems.
I have a database with two tables (UserData) and (UserDetails). I use the LINQtoEntities.
The issue here is that in the LINQ query is not accepted:
Details = c.ToList<UserDetails>()
Error is:
Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable<mynamespace.UserDetails>' to 'System.Collections.Generic.IEnumerable<System.Collections.IEnumerable>'
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public <List<UserDetails>> Details { get; set; }
}
public struct UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<UserDetails>() };
return Results;
}
Is there anybody who can help me out. In case more infos needed, please ask.
Thanks.
The following example is working. To get it working you can use object. See below the example:
public class UserData
{
public int Index{ get; set; }
public string Name{ get; set; }
public string PersonalNo { get; set; }
public List<object> Details { get; set; }
}
public class UserDetails
{
public int Age;
public string profession;
public string gender;
}
public IEnumerable<Userdata> GetUserData()
{
var context = new DatabaseEntities();
var Results =
from a in context.UserData
join b in context.UserDetails on a.Index equals b.Index into c
select new UserData{ Index = a.Index, Name = a.Name, PersonalNo = a.PersonalNo,
Details= c.ToList<object>() };
return Results;
}
The Type in the Watch windows is names as "object {MyTestApp.UserDetails}"
So basically it is working as I did it. But I need to cast it appropriate. Possibly now it is easier to help me.
Any suggestions?
I'm working with EF5. I've used code first approach. I got an error while using stored procedure. The error is
"The entity type CustomProduct is not part of the model for the current context."
In Db there are 3 tables.
Product
ProductId
ProductName
ProductDesription
ProuctVaraint
ProductVaraintId
ProductId
ProductVaraintName
Stock
Size
ProductPrice
ProductPriceId
ProudctId
Price
and Each entity has separate class with having all properties.
Product.cs
ProductVaraint.cs
ProductPrice.cs
Here is all classes
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
}
public class ProductVaraint
{
public int ProductVaraintId { get; set; }
public int ProductId { get; set; }
public string ProdcutVaraintName { get; set; }
public int Stock { get; set; }
public int Size { get; set; }
}
public class ProductPrice
{
public int ProductPriceId { get; set; }
public int ProductId { get; set; }
public decimal Price { get; set; }
}
public class CustomProduct
{
public int ProudctId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public int Stock { get; set; }
public int Size { get; set; }
public decimal Price { get; set; }
}
Here is stored Procedure
public IList<CustomProduct> ExecuteSP()
{
var context = ((IObjectContextAdapter)(this)).ObjectContext;
var connection = this.Database.Connection;
//open the connection
if (connection.State == ConnectionState.Closed)
connection.Open();
//create a command object
using (var cmd = connection.CreateCommand())
{
//command to execute
cmd.CommandText = "GetProducts";
cmd.CommandType = CommandType.StoredProcedure;
var reader = cmd.ExecuteReader();
var result = context.Translate<CustomProduct>(reader).ToList();
for (int i = 0; i < result.Count; i++)
result[i] = AttachEntityToContext(result[i]);
reader.Close();
return result;
}
}
}
public TEntity AttachEntityToContext<TEntity>(TEntity entity) where TEntity : BaseEntity, new()
{
var alreadyAttached = Set<TEntity>().Local.Where(x => x.Id == entity.Id).FirstOrDefault();
if (alreadyAttached == null)
{
Set<TEntity>().Attach(entity);
return entity;
}
else
{
return alreadyAttached;
}
}
I've mapped Product.cs,ProductVaraint.cs and ProductPrice.cs with DBContext but not mapped CustomProduct.cs
Now, I've made one stored procedure to return ProductName(from Product),ProductDescription(from product),Stock(from ProductVaraint),Size(from ProductVaraint) and Price(from ProductPrice).
To map this properties, I've a separate class called CustomProudct.cs that contains all those properties which is return by the stored procedure and map this class with store procedure.
There is no separate table for CustomProduct and I don't need to create extra table only for mapping sp result.
I know the causes that there is no separate table of CustomProduct and EF is trying to search in Db for this table and it does not find any table that's why it is throwing exception.
Please anyone suggest me how to do this. Is there any other way to handle this type of situation?
You should have something like
List<CustomProduct> lst = new List<CustomProduct>();
while reader.Read()
{
CustomProduct cp = new CustomProduct();
cp.ProductName = reader.GetString(0); --where 0 is the column index
.....
lst.Add(cp);
}
I don't know what AttachEntityToContext does, but as the name suggests, you are trying to attach this CustomProduct to the DbContext. It will not work because this is a class you created, with no correspondent in the DB.
I am displaying a record from my database. The record pulls data from other tables and uses a Int in the main table to represent the value so Item table has a Division equal to 1 and the Division table 1 = ALL . Now that i am displaying the records i am trying to turn the 1 into all. All the ID fields show the int. Which is what my code is telling it to do. But i am trying to display the name and when i do that i get a lot of red. It cannot find the name. CatagoryID should be CategoryName.
Hope that makes sense.
if (!IsPostBack)
{
string v = Request.QueryString["ContactID"];
int itemid;
int.TryParse(v, out itemid);
var customerInfo = GetCustomerInfo(itemid);
CONTACTID.Text = customerInfo[0].ContactID.ToString();
ContactTitle.Text = customerInfo[0].ContactTitlesID.ToString();
ContactNameB.Text = customerInfo[0].ContactName;
DropDownAddCategory.Text = customerInfo[0].CategoryID.ToString();
DDLAddDivision.Text = customerInfo[0].DivisionID.ToString();
ContactPhoneBox.Text = customerInfo[0].ContactOPhone;
ContactCellBox.Text = customerInfo[0].ContactCell;
ContactEmailBox.Text = customerInfo[0].ContactEmail;
CextB.Text = customerInfo[0].Ext;
}
private List<Solutions.Models.Contact> GetCustomerInfo(int itemid)
{
using (ItemContext context = new ItemContext())
{
return (from c in context.Contacts
where c.ContactID == itemid
select c).ToList();
}
}
This is the model
public class Contact
{
[ScaffoldColumn(false)]
public int ContactID { get; set; }
public System.DateTime ContactCreated { get; set; }
public string ContactName { get; set; }
public int? ContactTitlesID { get; set; }
public string ContactOPhone { get; set; }
public bool cApproved { get; set; }
public string User { get; set; }
public string ContactCell { get; set; }
public string ContactEmail { get; set; }
public int? DivisionID { get; set; }
public int? CategoryID { get; set; }
[StringLength(5)]
public string CExt { get; set; }
public virtual Division Division { get; set; }
public virtual Category Category { get; set; }
public virtual ContactTitle ContactTitle { get; set; }
public string Ext { get; set; }
}
With Entity Framework you can include related entities in query results:
return (from c in context.Contacts.Include("Catagory")
where c.ContactID == itemid
select c).ToList();
This will return contacts with Catagory objects: customerInfo.Catagory.CategoryName
BTW instead of returning list of contacts and selecting first one by index (thus possibly having index out of range exception), modify your method to return first contact (or default, if not found):
private Solutions.Models.Contact GetCustomerInfo(int itemid)
{
return (from c in context.Contacts.Include("Catagory")
where c.ContactID == itemid
select c).FirstOrDefault();
}
And use it this way:
var customerInfo = GetCustomerInfo(itemid);
if (customerInfo != null)
{
CONTACTID.Text = customerInfo.ContactID.ToString();
// etc
}
Are you using LINQ to SQL or Entity Framework? Check your model again and make sure the relationship between the two tables are setup correctly. The relationship may be missing from the model, and causing this problem.