var getdata = (DB.books.SqlQuery("select *
from book
inner join allclass on allclass.id = book.class_id_fk
inner join universty on universty.id = allclass.universty_id_fk")
).ToList();
I want to run this SQL query for joining table data in Entity Framework - how can I do this ?
Another way to do this with linq query but i want to get data with SQL query using Entity Framework
You cannot use DB.books if the result of the query is not of type books. You must instead use DB.Database class when the return type of the raw sql is not of any entity type from the database.
Follow these steps:
1) Create a model that matches your list of output columns like below.
public class MyModel
{
public string Column1{ get; set; }
public decimal Column2{ get; set; }
...
}
2) Alter your query like below.
var getdata = (DB.Database.SqlQuery<List<MyModel>>("select Column1,Column2.. //List all the columns instead of using *
from book
inner join allclass on allclass.id = book.class_id_fk
inner join universty on universty.id = allclass.universty_id_fk")
);
Related
I'm using EF Core 6 on a project. Most of my tables have a field like CreatedBy/UpdatedBy that includes a user id. There are only a few occasions where I need to show the full name associated with the user id, but that value is in another table in a different database, but on the same server.
Is creating a view that joins to the needed table only way to handle this? Could I create function in the database where my EF Core entities are modeled? How would that work code wise?
As EF context does not support cross database queries. Therefore, workaround can be a SQL view.
Is creating a view that joins to the needed table only way to handle this?
Yes you can do that. While creating view you should consider below way:
SELECT {Your 1st Table Column} [YourFirstDatabase].[dbo].[Your1stDbTable] WHERE UserId = (SELECT {Your 2nd Table Column} FROM [YourSecondDatabase].[dbo].[Your2ndDbTable] WHERE Category = 'Cat')
Could I create function in the database where my EF Core entities are modeled?
You could create function, stored procedure and view to achieve that. Afterwards, you should define that within a POCO Class finally call that on your context. For instance, here I am showing the example using a SQL view:
SQL view:
USE [DatabaseName_Where_You_Want_to_Create_View]
CREATE VIEW [ExecuteQueryFromOneDbToAnother]
AS
SELECT UserId, UserType,CreatedDate
FROM [RentalDb].[dbo].[Users]
WHERE UserId = (SELECT AnimalId
FROM [PetAnalyticsDb].[dbo].[Animal]
WHERE Category = 'Cat')
Note: I am simulating the example where I have two database from that I have two table where these columns, I would use in first database table UserId, UserType, CreatedDate and in second database from Animal table from the AnimalId I will search the user
How would that work code wise?
Following example would guided you how the implementation in the code should be.
Database context:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext (DbContextOptions<ApplicationDbContext > options) : base(options)
{
}
public DbSet<MultipleDBQueryExecutionModel> multipleDBQueryExecutionModels { get; set; }
override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MultipleDBQueryExecutionModel>().ToTable("ExecuteQueryFromOneDbToAnother");
}
}
Note: put your view name while map in DbContext to table ToTable("ExecuteQueryFromOneDbToAnother");. Here ExecuteQueryFromOneDbToAnother is the view name.
POCO class:
public class MultipleDBQueryExecutionModel
{
[Key]
public Int UserId { get; set; }
public string UserType { get; set; }
public DateTime CreatedDate { get; set; }
}
Controller:
[HttpGet]
public ActionResult GetDataFromDifferentDatabase()
{
var data = _context.multipleDBQueryExecutionModels.ToList();
return Ok(data);
}
Output:
Using ServiceStack.OrmLite with SQL Server I am trying to achieve a GROUP BY query over a mapped entity on to a DTO object but I can't seem to get the OrmLite syntax right.
The mapped entity looks like this:
public class MacRequestLetter
{
[PrimaryKey]
public Guid BatchId { get; set; }
[PrimaryKey]
public Guid Id { get; set; }
public DateTime LetterDate { get; set; }
/*
... elided - more properties relevant to this entity ...
*/
}
If I was writing the SQL manually this is what I'd write:
SELECT
BatchId
,COUNT(*) AS LetterCount
,MAX(LetterDate) AS LetterDate
FROM
dbo.MacRequestLetter
GROUP BY
BatchId
ORDER BY
LetterDate DESC
Here is the Ormlite query that I've attempted to achieve this with:
return db.Select<MacLetterBatch>(
db.From<MacRequestLetter>()
.Select(letter => new {
BatchId = letter.BatchId,
LetterCount = Sql.Count("*"),
LetterDate = Sql.Max(letter.LetterDate)
})
.GroupBy(letter => letter.BatchId)
.OrderByDescending(letter => Sql.Max(letter.LetterDate))
);
where MacLetterBatch is a DTO with properties matching the select part of the query.
However when I run this I get a sql error with message Column 'MacRequestLetter.LetterDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
The SQL that is sent to the server is:
SELECT "MacRequestLetter"."BatchId", "MacRequestLetter"."LetterDate"
FROM "MacRequestLetter"
GROUP BY "BatchId"
ORDER BY Max("LetterDate") DESC
which is clearly wrong in the way pointed out by the exception.
Can anyone tell me what is wrong with my OrmLite code? What code would achieve my goal?
I am trying to select only certain columns from a table using EF 6.1. However, it won't let me pull back just the columns I want. I have to pull back every column from the table which has 14,000 rows so the query takes ~30 seconds. The column that kills the query is a NVARCHAR in the table. But with EF it's all or nothing. I am using IEnumerable also. Perhaps I should be using IQueryable?>
Using this query I get an anonymous type error:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.Select(Function(S) New With {S.DateCreated, S.Description, S.PostRowID, S.Title}).OrderByDescending(Function(x) x.DateCreated)
Return posts.ToList
End Using
Error:
Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery`1[VB$AnonymousType_0`4[System.DateTime,System.String,System.Int32,System.String]]' to type 'System.Collections.Generic.IEnumerable`1
This works but is getting all the records and the columns I don't need:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.OrderByDescending(Function(x) x.DateCreated).ToList
Return posts
End Using
What I would do is:
Create PostSummaryDto class:
public class PostSummaryDto
{
public DateTime DateCreated { get; set; }
...rest of fields...
}
Use PostSummaryDto class in query:
New PostSummaryDto { DateCreated = S.DateCreated, ...}
Define return type of function as IEnumerable<PostSummaryDto>.
I am not a fan of Visual Basic, so I am not sure if returning anonymous types is allowed, but I believe it is good custom to define return types clearly.
In sql you can easily select a few columns out of the whole table. How do you achieve such a thing in JPA ?
And that's not actually my main question. It's more of an design one.
Let's say i have a parent object with some information fields and a collection of child objects field with a one to many connection.
#Entity
#Table(name = "code")
public class CodeList extends Code {
/** The code list's values. */
#OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "codeListId")
private List<CodeValue> codeValues;
/** The code list's display type. */
#Column(length = 255, name = "DISPLAY_TYPE")
private String displayType;
....
I am trying to implement a rest service using JPA (Hibernate) and jax-rs but what if i want my service to be able to retrieve just the information of the CodeList ( the displayType ) or just the collection of codeValues without any extra performance overhaul (nulling out the objects) or retrieval from the database of extra data that i dont need ?
By default #OneToMany relationship is LAZY .
simple value :
SELECT c.displayType FROM CodeList c WHERE c.id=:id
relationship
SELECT v FROM CodeList c LEFT JOIN c.codeValues v WHERE c.id=:id
Use JPQL to determine which values you want to retrieve.
select e.displayType from CodeList e
OR
select e from CodeList d left join fetch d.codeValues e
I know there have been a lot of questions about Entity Framework doing cross database queries on the same server posted to stackoverflow. Mostly the answer seems to be 'no', and this link from way back in 2008 is referenced. However, Entity Framework is changing all the time and with CTP5 out, I'm wondering if the answer is still the same - that you can't do it, or you can do it if you manually edit the edmx file, or you have to use views. This feature alone is the reason I'm still tied to Linq-to-SQL, as we have multiple SQL Server 2008 databases on the same server and need to query across them. Polluting our databases with hundreds of select * views is not an option, and with code-first development I don't have an edmx file to edit. I was playing with the pubs database to see if I could get somewhere, but I'm stuck. Any suggestions?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
namespace DbSchema {
public class Employee {
[Key]
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public short JobID { get; set; }
public Job Job { get; set; }
}
public class Job {
[Key]
public short ID { get; set; }
public string Description { get; set; }
}
public class PubsRepository : DbContext {
public DbSet<Employee> Employee { get; set; }
public DbSet<Job> Job { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
// employee
var eeMap = modelBuilder.Entity<Employee>();
eeMap.ToTable("employee", "dbo"); // <-- how do I reference another database?
eeMap.Property(e => e.ID).HasColumnName("emp_id");
eeMap.Property(e => e.FirstName).HasColumnName("fname");
eeMap.Property(e => e.LastName).HasColumnName("lname");
eeMap.Property(e => e.JobID).HasColumnName("job_id");
// job
var jobMap = modelBuilder.Entity<Job>();
jobMap.Property(j => j.ID).HasColumnName("job_id");
jobMap.Property(j => j.Description).HasColumnName("job_desc");
}
public List<Employee> GetManagers() {
var qry = this.Employee.Where(x => x.Job.Description.Contains("manager"));
Debug.WriteLine(qry.ToString());
return qry.ToList(); // <-- error here when referencing another database!
}
}
}
I think that the answer is still no, but there are ways around it.
The reason why it is no, it that EF uses a DBContext, and a context has a connection string, and a connection string goes to a database.
Here are 2 ways around it:
use 2 different contexts one against each database, this will mean bringing data to the client and merging it on the client.
use linked tables on the database, pulling data through views, so that EF sees it as coming from a single database.
In your code it looks like you are using 2 dbcontexts
There are two ways to do it.
One is, of course, to create a view in one of the databases which does the cross database query, then access the veiw from your model as you would any other view.
The other was it to create the same cross database query view within the model itself by creating a DefiningQuery. This is most similar to how you would do it with SQLClient. In SQLClient, you'd create the view in T-SQL as the text of a SQLCommand, then execute the command to create a data reader or data table. Here you use the same T-SQL to create a DefiningQuery, then link it up with an Entity that you create manually. It's a bit of work, but it does exactly what you'd want it to.
Here's a link on using DefiningQuerys: http://msdn.microsoft.com/en-us/library/cc982038.aspx.
If you happen to have the book "Programming Entity Framework" by Lerman from O'Reilly, there a good example in chapter 16.
So you have to jump through a few hoops to do what you used to do directly with SQLClient, BUT you get the modeled Entity.
The answer is still the same. If you want to execute cross database query you have to fall back to SQL and use SqlQuery on context.Database.
Warning! using DefiningQuerys can be VERY SLOW!
Here's an example:
If this is the defining query that you create an Entity against:
Select
C.CustomerID,
C.FirstName,
C.LastName,
G.SalesCatetory
From
CustomerDatabase.dbo.Customers C
Inner Join MarketingDatabase.dbo.CustomerCategories G on G.CustomerID = C.CustomerID
Then when you do a select against the Entity by CustomerID, the SQL trace looks something like this:
Select
[Extent1].[CustomerID] as [CustomerID],
[Extent1].[FirstName] as [FirstName],
[Extent1].[LastName] as [LastName],
[Extent1].[SalesCatetory] as [SalesCatetory]
From (
Select
C.CustomerID,
C.FirstName,
C.LastName,
G.SalesCatetory
From
CustomerDatabase.dbo.Customers C
Inner Join MarketingDatabase.dbo.CustomerCategories G on G.CustomerID = C.CustomerID
) as [Extent1]
Where '123456' = [Extent1].[CustomerID]
SQL Server may run this query very slowly. I had one case, a little more complicated than the above example, where I tried the DefiningQuery text directly in a SQl Server Management Console query window by adding a where clause for the value I wanted to select for. It run in less than a second. Then I captured the SQL Trace from selecting for the same value from the Entity created for this DefiningQuery and ran the SQL Trace query in a SQL Server query window - it took 13 seconds!
So I guess that only real way to do cross database queries is to create a veiw on the server.