How to execute a multi-table query in code-first approach of Entity Framework? - entity-framework-4.1

If I want to execute a query that is based on joins between multiple tables, then how would this be coded in a code-first approach using Entity Framework 4.1? For example, I want to execute the following query:
SELECT p.ProductId
, p.Name AS ProductName
, c.Name AS CategoryName
FROM
Products p
INNER JOIN Categories c
ON c.CategoryId = p.CategoryId

You will create classes like:
public class Product {
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
And you will use this query where join will be created automatically from navigation properties:
var query = from p in context.Products
select new {
ProductId = p.ProductId,
ProductName = p.Name,
CategoryName = p.Category.Name
};

Related

How to convert SQL Server query to JSON

I need to build a table in a view using the result of this SQL Query
SELECT f.empresaid,
e.fantasia AS Empresa,
f.filialid,
f.fantasia AS Filial,
u.consultorid AS ConsultorID,
cs.nome AS Consultor,
'' AS Midia,
fp.campoextra,
Count(DISTINCT p.usuarioid) AS Total,
Count(DISTINCT u.ativacao) AS TotalAtivos,
Iif(Count(DISTINCT p.usuarioid) > 0, ( Cast(
Count(DISTINCT u.ativacao) AS DECIMAL) / Count(DISTINCT p.usuarioid) ), 0
) * 100
AS Porcentagem
FROM formas_pagamento fp
INNER JOIN usuarios u
ON u.forma_pagamentoid = fp.forma_pagamentoid
INNER JOIN pagamentos p
ON p.usuarioid = u.usuarioid
AND p.tipo = 'MTU'
INNER JOIN cartoes c
ON c.usuarioid = u.usuarioid
AND c.dependenteid = 0
INNER JOIN midias m
ON m.descricao = u.midia
INNER JOIN consultores cs
ON cs.consultorid = u.consultorid
INNER JOIN filiais f
ON f.filialid = u.filialid
INNER JOIN empresas e
ON e.empresaid = f.empresaid
WHERE c.dependenteid = 0
AND u.cadastro > '2019-07-01'
AND u.cadastro < '2019-08-01'
AND u.filialid = 3
GROUP BY f.empresaid,
e.fantasia,
f.filialid,
f.fantasia,
u.consultorid,
cs.nome,
fp.campoextra
ORDER BY empresaid,
filialid,
consultor,
campoextra
Which gives me this result, the table in the view should be created with the structure as follows table structure and organization. I was trying to load this query data directly from my ViewModel List but that went heavy, if I could have a json array as following : JSON I could build the table with that desired structure more easily, can anyone help ? Thanks !
----------------------------------EDIT-------------------------------------
public List<ViewModelOrigemEConsultor> GetConsultorOrigem ()
{
var Lista = new List<ViewModelOrigemEConsultor>();
/*string SQL = SQL QUERY GOES HERE */
var cnn = CnnDB.OpenDB();
using (cnn)
{
var cmd = new SqlCommand(SQL, cnn);
cnn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
decimal Porcentagem = 0;
while (reader.Read())
{
Porcentagem = (decimal)(Convert.ToInt32(reader["TotalAtivos"]) / Convert.ToInt32(reader["Total"]));
Lista.Add(new ViewModelOrigemEConsultor
{
EmpresaID = Convert.ToInt32(reader["EmpresaID"]),
Empresa = reader["Empresa"].ToString(),
FilialID = Convert.ToInt32(reader["FilialID"]),
Filial = reader["Filial"].ToString(),
ConsultorID = Convert.ToInt32(reader["ConsultorID"]),
Consultor = reader["Consultor"].ToString(),
Midia = reader["Midia"].ToString(),
FormaPagamento = reader["FormaPagamento"].ToString(),
Total = Convert.ToString(string.Format("{0:N}", reader["Total"])),
TotalAtivos = Convert.ToString(string.Format("{0:N}", reader["TotalAtivos"])),
Porcentagem = Convert.ToString(string.Format("{0:N}", Porcentagem))
});
};
}
};
return Lista;
}
MODEL
public class ViewModelOrigemEConsultor
{
public int EmpresaID { get; set; }
public string Empresa { get; set; }
public int FilialID { get; set; }
public string Filial { get; set; }
public int ConsultorID { get; set; }
public string Consultor { get; set; }
public string Midia { get; set; }
public string FormaPagamento { get; set; }
public string Total { get; set; }
public string TotalAtivos { get; set; }
public string Porcentagem { get; set; }
}
If you've got the list of objects populated and are just looking to convert it to JSON simply use something like https://www.nuget.org/packages/Newtonsoft.Json and then serialize the list to json. In this case it would be similar to:
var json = JsonConvert.SerializeObject(model);

PetaPoco Insert/Update

I have a table with the following field. I am not able to update the existing values in the table. I want to update it based on the SourceId which is not a Primary key (Id is the primary key). Below is the class representation.
I do not want to modify the PetaPoco.cs file. Please help. Thank you.
[TableName("Incident")]
[PrimaryKey("Id", AutoIncrement = true)]
public class Incident
{
public int Id { get; set; }
public string SourceId { get; set; }
public int AgencyId { get; set; }
public DateTime? OccurredOn { get; set; }
public DateTime? ImportedOn { get; set; }
public DateTime? LastUpdatedOn { get; set; }
}
You can select the record using the SourceID and then update it.
Example:
var rec = db.FirstOrDefault<Incident>("WHERE SourceID = #0", SourceID);
rec.AgencyId = NewValueForAgencyId;
db.Update(rec);

Need help in solving SQL

I am new in Asp.net
now i want to try to start a social network project
I have 3 tables
User
Userid
-Username
-Email
-Password
-Name
-Profilepic
Post
-Postid -Content -Postdate -Userid
Friendlist
Friendlistid - userid - friendid -status
i want to load the post that from my friend and myself
This is my sql code
select b.userid, a.Friendid, c.name, b.postid, b.Content, b.postdate, c.profilepic
from friendlist a
left join [user] c on a.friendid = c.userid
left join post b on a.friendid = b.userid
where a.userid = 1 AND a.Status = 1 OR a.Userid = 1
ORDER BY postid desc
The problem that i faced was my post will repeat
For example, my friendlist table has 3 friends, my every single post will repeat 3 times and my friend post stay normal.
Any solution for this sql code?
If you have a relationship between the tables and are using Entity Framework. You can simply invoke the tables below its "friendlist". You can take this query return creating a class specific to this return
public class ListFriendsGroup
{
public int UserId { get; set; }
public int friendId { get; set; }
public int PostId{ get; set; }
public string Name { get; set; }
public string Content { get; set; }
public DataTime PostData { get; set; }
public string ProfilePic { get; set; }
}
var friendlist = Context.friendList.Include("user").Include("post")
// HERE .GroupBy(...
.Select(f => new ListFriendsGroup() { Userid = f.post.userid, FriendId = f.Friendid, Name = f.user.name, PostId = f.post.postid, Content = f.post.Content, PostData = f.post.postdate, Profilepic = f.user.profilepic }).ToList()
Read about the Group By clause to perform grouping of data
Group by, Count and Lambda Expression

LINQ to SQL - Searching column of joined table

I am trying to return a result set that includes rows where any of three strings has a string match. My domain models look like this:
public class Customers
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BidNames
{
public int BidNameID { get; set; }
public int CustomerID { get; set; }
public string BidName { get; set; }
}
There is a FK between BidName.CustomerID and Customers.CustomerID and it is a one-to-many relationship where there can be multiple BidNames for a single Customer. When searching my customer table I want to bring back all records where there is a string match in FirstName, LastName or any of the associated BidNames. For this example I'll use a BidName search string of "ba".
from c in Customers
where c.FirstName.Contains("ba") || c.LastName.Contains("ba") || c.BidNames.Any(b=>BidNames.BidName.Contains("ba"))
orderby c.LastName, c.FirstName
select new { CustomerID = c.CustomerID, FirstName = c.FirstName, LastName = c.LastName }
It all works until I add the final criteria in the Where clause. I understand that c.BidNames is a collection and I'm looking to see if Any of them have a BidName that contains "ba". Where I'm running into trouble is trying to specify the BidNames.BidName column to search for the string. The code I've written above fails with "BidNames does not contain a definition for 'BidName'"
How do I write the last part of the Where clause so I can search all the BidNames.BidName fields associated with the Customer record? I hope and assume I can use the same syntax to specify the BidName field in the orderby and select clauses as well.
Many thanks,
BK
FINAL ANSWER:
from c in Customers
where
c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
orderby
c.LastName,
c.FirstName
select new {
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName,
BidNames = c.BidNames.OrderBy(b=>b.BidName)
}
Try changing your where clause to
Where c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
In your Any clause, b is an instance of the BidNames class, so you want to access properties of that rather than the BidNames property of the Customer.

How do I configure EF 4.1 to correctly model a non standard relationship

I have the following model which is unchangeable:
Person
-------
int Id (PK)
int CompanyId
bool Deleted
Company
-------
int Id (PK)
int DefaultIdentifierId
Identifier
-------
int PersonId (PK)
int DefaultIdentifierId (PK)
string Identifier
I have created classes for each table but I'm struggling to specify the mappings to the database correctly. I need to be able to return the Id of a non deleted person given the company id and Identifer. In sql this would be a join between Company and Identifer via DefaultIdentifierId and a join between Person and Identifier via PersonId but I can't seem to get this specified correctly.
The problem is that you can't have navigation properties between Company and Identifier because neither DefaultIdentifierId in Company nor DefaultIdentifierId in Identifier are primary keys. (In Identifier it's only part of the key.) You can model a one-to-many relationship between Company and Person and between Person and Identifier though. So you could try these model classes:
public class Person
{
public int Id { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
public bool Deleted { get; set; }
}
public class Company
{
public int Id { get; set; }
public int DefaultIdentifierId { get; set; }
}
public class Identifier
{
[Key, Column(Order = 1)]
public int PersonId { get; set; }
[Key, Column(Order = 2)]
public int DefaultIdentifierId { get; set; }
public string IdentifierString { get; set; }
public Person Person { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Identifier> Identifiers { get; set; }
}
The Id in the name DefaultIdentifierId of Company is misleading. In this model this property is a simple scalar property and not a Foreign Key property which belongs to any navigation property.
To run the query you want you will have to use a Join in LINQ since you cannot navigate from Company to Identifier through navigation properties:
int companyId = 1;
string identifierString = "ABC";
List<int> personIds = context.Identifiers
.Join(context.Companies,
i => i.DefaultIdentifierId,
c => c.DefaultIdentifierId,
(i, c) => new { i, c })
.Where(a => a.c.Id == companyId
&& a.i.IdentifierString == identifierString
&& !a.i.Person.Deleted)
.Select(a => a.i.Person.Id) // or a.i.PersonId should work as well
.ToList();
The result is not necessarily unique but a list of Person Ids.