Return multiple tables in one SQL Connection using Entity Framework - sql-server

When i use Entity Framework Profiler the following code makes 3 calls to the database.
using (var entities = new Entities())
{
var faqs = entities.Table1.ToList();
var latest = entities.Table2.ToList();
var inst = entities.Table3.ToList();
}
I would like to make one database call, is there anyway to do this without calling a stored procedure?
I am trying to eliminate database calls throughout my application.

You can do a cross join in ef,
See this
http://geekswithblogs.net/berthin/archive/2012/05/25/how-to-perform-cross-join.aspx

My problem was solved by using the nuget package EntityFramework.Extended.
So using my original code, this is how you would solve my issue.
using (var entities = new Entities())
{
var faqs = entities.Table1.Future();
var latest = entities.Table2.Future();
var inst = entities.Table3.Future();
inst.ToList();
}
When you call ToList() a batch call is sent to your database in one connection.
The reference link is below:
https://github.com/loresoft/EntityFramework.Extended/wiki/Future-Queries

Related

Dotmim.Sync is throwing exception when synchronizing existing SQLite with SQL Server databases

I get a Dotmim.Sync.SyncException when calling the agent.SynchronizeAsync(tables) function:
Exception: Seems you are trying another Setup tables that what is stored in your server scope database. Please make a migration or create a new scope
This is my code:
public static async Task SynchronizeAsync()
{
var serverProvider = new SqlSyncProvider(serverConnectionString);
// Second provider is using plain old Sql Server provider, relying on triggers and tracking tables to create the sync environment
var clientProvider = new SqliteSyncProvider(Path.Combine(FileSystem.AppDataDirectory, "treesDB.db3"));
// Tables involved in the sync process:
var tables = new string[] { "Trees" };
// Creating an agent that will handle all the process
var agent = new SyncAgent(clientProvider, serverProvider);
// Launch the sync process
var s1 = await agent.SynchronizeAsync(tables);
await agent.LocalOrchestrator.UpdateUntrackedRowsAsync();
var s2 = await agent.SynchronizeAsync();
}
I'm the author of Dotmim.Sync
Do not hesitate to to fill an issue on Github if you are still struggling.
Regarding your issue, I think you have made some tests with different tables.
You need to stick with a set of tables, because DMS needs to create different things (triggers / stored proc and so on)
If you want to test different setups, you need to define differents scopes.
You have a complete documentation on https://dotmimsync.readthedocs.io/

Quartz.net Manually trigger job from Web API

I realize this has sort of been asked before but I want to get a clear confirmation.
I have a Windows Service running the Quartz.Net Scheduler. Jobs and Triggers have been created.
We will have an angular web client that will at times, need to fire jobs manually.
So in a Web API Controller, I have code like this:
var properties = new NameValueCollection
{
["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
["quartz.jobStore.useProperties"] = "true",
["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz",
["quartz.jobStore.dataSource"] = "myDS",
["quartz.jobStore.tablePrefix"] = "QRTZ_",
["quartz.dataSource.NAME.provider"] = "SqlServer",
["quartz.dataSource.NAME.connectionString"] = "Server=localhost;Database=QuartzScheduler;Uid=blahuser;Pwd=blahpwd",
["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"
};
var sched = new StdSchedulerFactory(properties).GetScheduler().Result;
var jobKey = new JobKey("DailyJob1130EST", "DailyGroup");
var jobDataMap = new JobDataMap();
jobDataMap.Add("listIds", "33333");
sched.TriggerJob(jobKey, jobDataMap);
The Job Name and Group do exist in the database.
I was hoping that the call to TriggerJob would cause the Scheduler I have running in my windows service, to fire the job. But it doesn't. Nothing happens, not even an error.
BTW, I don't want to use remoting since it requires the full .NET Framework and the help docs say that it is considered unsafe.
If TriggerJob doesn't work, I guess to run a job manually I'd have to add a new trigger to the scheduler to run once, or something???
There may be other ways, but one way that I was able to successfully do it was:
var sched = await new StdSchedulerFactory(properties).GetScheduler();
var jobKey = new JobKey("DailyJob1130EST", "DailyGroup");
var jobDataMap = new JobDataMap();
jobDataMap.Add("listIds", rInt.ToString());
var trig = TriggerBuilder.Create()
.WithIdentity("RunNowTrigger")
.StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5)))
.WithDescription("Run Now Trigger")
.Build();
sched.TriggerJob(jobKey, jobDataMap);
Note: "properties" were my NameValueCollection config information, which I omitted from the sample code. It was nothing out of the ordinary. It just setup the jobStore, dataSource, serializer.type and threadPool.type settings.

nHibernate only returns an empty row set

I profile the SQL server and don't see any attempt to hit the server from Hibernate.Also no errors thrown.The only thing that happens is Hibernate returns an empty row set.
The query:
var cfg = new Configuration();
cfg.Configure();
ISessionFactory sesFactory = cfg.BuildSessionFactory();
var ses = sesFactory.OpenSession();
var qry = ses.CreateQuery("from Tko.SmartMoves.Modules.Operations.Domain.vDoors");
IList<vDoors> x = qry.List<vDoors>();
If I set the same thing up using ICriteria I have the same problem.
But this works ~ all other things being equal:
string sql = string.Format("select * from vDoors");
var cfg = new Configuration();
cfg.Configure();
ISessionFactory sesFactory = cfg.BuildSessionFactory();
var ses = sesFactory.OpenSession();
var qry = ses.CreateSQLQuery(sql);
IList<vDoors> x = qry.List<vDoors>();
Thanks.
On testing (because of what I posted that was prompted by Oskar Berggren, thank you Oskar) I recognized my vDoors.hbm.xml file was actually named vDoors.xml (without the .hbm.) I move to suggest the nHibernate crew immediately release a version that throws an error under the circumstance where nHibernate can't find the necessary mapping resource at run-time.
Thanks again Oskar #OskarBerggren

Does Npgsql provider has support for TransactionScope?

I'm trying to use a TransactionScope with the Npgsql provider.
I found in an old question (provider for PostgreSQL in .net with support for TransactionScope) that Npgsql didn't supported it yet.
Now, after about 5 years, does Npgsql support TransactionScope?
I made a test for myself, using Npgsql 3.0.3 and using the following code:
using (var scope = new TransactionScope())
{
using(var connection = new Npgsql.NpgsqlConnection("server=localhost;user id=*****;password=*****database=test;CommandTimeout=0"))
{
connection.Open();
var command = new NpgsqlCommand(#"insert into test.table1 values ('{10,20,30}', 2);");
command.Connection = connection;
var result = command.ExecuteNonQuery();
// scope.Complete(); <-- Not committed
}
}
Anyone can confirm that Npgsql doesn't support TransactionScope?
EDIT #1
After the confirmation of the support of Npgsql to the TransactionScope, I found that you need to be sure to haev Distribuited Transaction enabled in your PostgreSQL configuration, checking the max_prepared_transactions parameter in the postgres.conf file (remember to restart your server).
EDIT #2
I enabled the Distribuited Transaction on my server but now I got an error using the TransactionScope with Npgsql.
This is my code:
using (var sourceDbConnection = new NpgsqlConnection(SourceConnectionString))
using (var destinationDbConnection = new NpgsqlConnection(DestinationConnectionString))
using (var scope = new TransactionScope())
{
sourceDbConnection.Open();
destinationDbConnection.Open();
Logger.Info("Moving data for the {0} table.", TableName.ToUpper());
var innerStopWatch = new Stopwatch();
innerStopWatch.Start();
foreach (var entity in entities)
{
var etlEntity = new EtlInfoItem
{
MigratedEntityId = category.RowId,
ProjectId = category.ProjectId,
ExecutionDatetime = DateTime.Now
};
// Insert into the destination database
var isRowMigrated = InsertEntity(entity, DestinationSchema, destinationDbConnection);
if (isRowMigrated)
{
// Update the ETL migration table
InsertCompletedEtlMigrationEntity(etlEntity, EtlSchema, sourceDbConnection);
}
else
{
// Update the ETL migration table
InsertFailedEtlMigrationEntity(etlEntity, EtlSchema, sourceDbConnection);
}
}
Logger.Info("Data moved in {0} sec.", innerStopWatch.Elapsed);
Logger.Info("Committing transaction to the source database");
innerStopWatch.Restart();
scope.Complete();
innerStopWatch.Stop();
Logger.Info("Transaction committed in {0} sec.", innerStopWatch.Elapsed);
}
When the TransactionScope exits from the scope (when exiting the using statement), I get a Null Reference Exception with the following stack trace:
Server stack trace:
at Npgsql.NpgsqlConnector.Cleanup()
at Npgsql.NpgsqlConnector.Break()
at Npgsql.NpgsqlConnector.ReadSingleMessage(DataRowLoadingMode dataRowLoadingMode, Boolean returnNullForAsyncMessage)
at Npgsql.NpgsqlConnector.ReadExpectingT
.........
It happens randomly.
Npgsql does support TransactionScope and has done so for quite a while. However, at least for the moment, in order to have your connection participate in the TransactionScope you must either:
Include Enlist=true in your connection string, or
Call NpgsqlConnection.EnlistTransaction
Take a look at the Npgsql unit tests around this for some examples.

Why is the Entity Framework inserting when it should update?

I use the following RIA Services call to register and return a Project entity.
// On Server; inside RIA Domain Service
[Invoke]
public Project CreateNewProject(String a_strKioskNumber)
{
Decimal dProjectID = ObjectContext.RegisterProjectNumber(a_strKioskNumber)
.FirstOrDefault() ?? -1m;
// Tried this but it returned zero (0)
//int nChanged = ObjectContext.SaveChanges();
var project = (from qProject in ObjectContext.Projects.Include("ProjectItems")
where qProject.ID == dProjectID
select qProject)
.FirstOrDefault();
if (project == null)
return null;
return project;
}
As you can see, it calls a stored procedure that returns a project ID. It uses this ID to look up the Project entity itself and return it. When the Project entity is returned to the client it is detached. I attach it to the DomainContext and modify it.
// At Client
_activeProject = a_invokeOperation.Value; // <-- Detached
_context.Projects.Attach(_activeProject); // <-- Unmodified
if (_activeProject != null)
{
_activeProject.AuthenticationType = "strong"; // <-- Modified
_activeProject.OwnerID = customer.ID;
_projectItems.Do(pi => _activeProject.ProjectItems.Add(pi));
_activeProject.Status = "calculationrequired";
}
At this point it has an entity state of Modified. When I submit changes it gives me an exception regarding a UNIQUE KEY violation as if it is trying to insert it rather than update it.
// At Client
_context.SubmitChanges(OnProjectSaved, a_callback);
I'm using the same DomainContext instance for all operations. Why should this not work?
What's going wrong? This is rather frustrating.
Edits:
I tried this (as suggested by Jeff):
[Invoke]
public void SaveProject(Project a_project)
{
var project = (from qProject in ObjectContext.Projects
where qProject.ID == a_project.ID
select qProject)
.FirstOrDefault();
project.SubmitDate = a_project.SubmitDate;
project.PurchaseDate = a_project.PurchaseDate;
project.MachineDate = a_project.MachineDate;
project.Status = a_project.Status;
project.AuthenticationType = a_project.AuthenticationType;
project.OwnerID = a_project.OwnerID;
project.ProjectName = a_project.ProjectName;
project.OwnerEmail = a_project.OwnerEmail;
project.PricePerPart = a_project.PricePerPart;
project.SheetQuantity = a_project.SheetQuantity;
project.EdgeLength = a_project.EdgeLength;
project.Price = a_project.Price;
project.ShipToStoreID = a_project.ShipToStoreID;
project.MachiningTime = a_project.MachiningTime;
int nChangedItems = ObjectContext.SaveChanges();
}
It did absolutely nothing. It didn't save the project.
What happens if you add a SaveProject method on the server side and send the object back to the server for saving?
I've not done EF with RIA Services, but I've always sent my objects back to the server for saving. I'm assuming that SubmitChanges call you are making wires up everything properly for you for sending it back to the server, but perhaps it is doing something wrong and handling it manually will fix it.
I dont have the source at the moment but I have seen it recommended that you use a new context for each operation in Silverlight. I ran into a similar problem today and it was because I was using a Service level context that was remembering previous values that I didnt want, I changed to creating a new context for each service call and the behavior became what I expected.
public void SaveResponses(ICollection<Responses> items, Action<SubmitOperation> callback)
{
try
{
SurveysDomainContext _context = new SurveysDomainContext();
foreach (Responses item in items)
{
_context.Responses.Add(item);
}
_context.SubmitChanges(callback, null);
}
catch (Exception)
{
throw;
}
}
As for the notion that one can't use a singleton global DomainContext, this is actually debatable. In my project I use a singleton DomainContext with no issues. In other projects, we have created a new DomainContext for different modules in the app where the entities are reused. There are definitely pros and cons. See:
Strategies for Handling Your DomainContext (external blog)
It seems that the problem is that when you attach your project to the DomainContext it checks the _context.Projects entityset and isn't finding an entity with that primary key, and then assumes that the newly attached entity doesn't exist serverside yet and that submitting changes should insert it. A possible workaround might be to explicitly load the newly created Project into the DomainContext. It would ensure that it sets the correct state on the entity--that is, that the project already exists on the server and that that it's an update instance, rather than an insert instance.
So maybe something like:
//after your Project has already been created serverside with the invoke
_context.Load(_context.SomeQueryThatLoadsYourNewlyCreatedProject(), LoadBehavior.RefreshCurrent, (LoadOperation lo) => {
Project project = lo.Entities.FirstOrDefault(); //is attached and has correct state
if (project != null)
{
project.AuthenticationType = "strong";
project.OwnerID = customer.ID;
project.Do(pi => _activeProject.ProjectItems.Add(pi));
project.Status = "calculationrequired";
_context.SubmitChanges(); //hopefully will trigger an update, rather than an insert
}
});

Resources