.Net Core query data from 2 different databases - c#

I have a .Net Core project running and I am utilizing 2 different databases (A MySQL db and a PostGreSQL db). I have them set up and they are both implemented in my current controller - TripController.cs
TripController.cs
public IActionResult Index()
{
var viewModels = new List<TripViewModel>();
var Dids = _tripContext.Dids.ToList();
foreach (var Did in Dids)
{
IQueryAble<Tripmetadata> trips = _tripContext.Tripmetadata.Where(t => t.Did == Did.Did);
var tripsCount = trips.Count()
//--------------------- I believe error is here ---------------------
var alias = _context.Devices.Where(d => (long.Parse(d.Did)) == Did.Did).Select(d => d.Alias).ToString();
// ------------------------------------------------------------------
var viewModel = new TripViewModel
{
TripCount = tripsCount,
didElement = Did,
Alias = alias
};
viewModels.Add(viewModel)
}
return View(viewModels);
}
_context is the MySQL db and _tripContext is the PostGreSQL db.
Both database have a field called Did which I need to use. For the PostGreSQL db I need to use it to get the amount of trips (tripCount) for a given Did. However for the MySQL db I need to use the Did to get the alias for a device.
When I try to use the above code from the TripController to get the alias for a Did I get a weird value when displaying it in my view:
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[System.String]
as seen here:
I use a viewModel called TripViewModel which I pass to my View:
TripViewModel.cs
public class TripViewModel
{
public int TripCount {get;set;}
public long DidElement {get;set;}
public string Alias {get;set;}
}
How do I get it write the right Alias in my view?
I have tried numerous methods that doesn't yield the result I need.

I managed to find the solution.
My problem was not adding a .Single() at the end of my EF query.
I also found that this post is a duplicate. However I didn't know what my problem was until a stumpled upon this:

Related

Entity Framework context "not freshed"?

Platform: .net core 3.1 and Oracle 11g.
Here's my C# code snippet:
// this puts the value "00000000-0000-00" in ExtRef
// On the database end, there's a before-insert trigger that overwrites this value
newCustomer.ExtRef = Guid.Empty.ToString().Substring(0, 16);
using CustomerContext cntxt =
new CustomerContext(connectionStrings[MySchema]);
cntxt.Customer.Add(newCustomer);
cntxt.SaveChanges();
Customer saved =
cntxt.Customer
.AsQueryable()
.Where(customer => customer.Name1 == newCustomer.Name1)
.Single();
// Though the database reflects a new value for the ExtRef, this call still returns 00000000-0000-00
output.WriteLine($"{saved.ExtRef}");
I tried with a new instance of the context and the ExtRef has the value in the database. Is there a way that I can get the updated ExtRef value without using the 2nd context?
Thanks!
You want to mark the ExtRef field in the entity as DatabaseGenerated(DatabaseGeneratedOption.Computed). This tells EF to expect the value to be set on insert, so you can read it after SaveChanges.
public class Customer
{
// ...
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string ExtRef { get; set; } = "00000000-0000-00"; // Set a default here.
}
Then this should work as expected:
// newCustomer.ExtRef = Guid.Empty.ToString().Substring(0, 16); Not needed.
using CustomerContext cntxt = new CustomerContext(connectionStrings[MySchema])
{
cntxt.Customer.Add(newCustomer);
cntxt.SaveChanges();
}
output.WriteLine($"{newCustomer.ExtRef}");

How to execute a stored procedure join without creating a new asp.net model?

I am creating stored procedures in SQL Server database and have been having issues returning the data when called.
I have managed to get it to work, but it feels as if it is a hack job and that I am doing it incorrectly. Please see the code below and let me know if there is a better way to go about doing this. Thank you for taking the time to help me.
create procedure FetchSumOfEmpSalariesByCity
as
begin
select
sum(e.SAL) as TotalSalary, d.LOC as Location
from
EMPS e
join
DEPTs d on e.DEPTNO = d.DEPTNO
group by
d.LOC
end
public class SumOfEmpsSalaryByCity
{
[Key]
public int TotalSalary { get; set; }
public string Location { get; set; }
}
[HttpGet]
[Route("salary")]
public IHttpActionResult GetEMPsSal()
{
using (var db = new KemmitContext())
{
var sp = db.SumOfEmpsSalaryByCities.SqlQuery("FetchSumOfEmpSalariesByCity");
return Ok(sp.ToList());
}
}
I want to do this the correct way. Is there a way to do this without a model? Or am I going about this the right way?
I break these tasks down like this; should it be done with EF or in the database and if it's in the database, should it be a View or an Sp?
Whenever I'm simply selecting data, I use EF either direct to the table for very simple queries or I create a database View for any joins, etc. This can be done in EF but it's god-awful, in any case, IMO these tasks belong in the database, right tool, right job. If you're using code-first, getting your Views across is a bit involved, let me know if you're doing that.
var model = db.v_ObservationAutoComplete // This can be direct to a table or a view
.Where(oa => oa.Observation.Contains(term))
.OrderBy(oa => oa.Observation)
.Select(oa => new
{
label = oa.Observation
}).Take(10);
When I have to update something in a single table, I use EF
t_Section eSection = new t_Section
{
SectionId = model.SectionId,
Section = model.Section,
SectionTypeId = model.SectionTypeId,
SectionOrdinal = model.SectionOrdinal,
ModifyDate = DateTime.Now,
ModifyUserName = User.Identity.Name,
LastChangeId = newChangeId
};
db.Entry(eSection).State = EntityState.Modified;
db.SaveChanges();
If I have to do a multi-table update, I have a couple of different methodologies; 1) returning a simple bool value for a status code/scalar value, or I have to return a result set after doing whatever update I made.
This returns a List
List<string> elements = new List<string>();
try
{
SqlParameter[] parms = new[]
{
new SqlParameter("mpid", myProtocolsId),
new SqlParameter("elid", elementId)
};
elements = db.Database.SqlQuery<string>("p_MyProtocolsOverviewElementRemove #myProtocolsId = #mpid, #elementId = #elid", parms).ToList();
return Json(elements);
}
catch (Exception e)
{
return Json(null);
}
And if I just need a simple value back, something like this;
SqlParameter[] parms = new[]
{
new SqlParameter("chid", changeId),
new SqlParameter("prid", change.ObjectId),
new SqlParameter("psid", change.ProtocolSectionId),
new SqlParameter("inid", change.SecondaryObjectId),
new SqlParameter("acun", User.Identity.Name)
};
result = db.Database.SqlQuery<int>("p_MyProtocolsContentUpdateInterventionAdd #changeId = #chid, #protocolId = #prid, #protocolSectionId = #psid, #interventionId = #inid, #acceptUserName = #acun", parms).FirstOrDefault();
Hope this helps!

Linq to SQL including a db function

I am trying to recover data from an SQL Server 2016 db.
To start, I have used the POCO class generator to create by datacontext, this contains a definition for the function I want to use.
// Table Valued Functions
[System.Data.Entity.DbFunction("DbContext", "GetData")]
[CodeFirstStoreFunctions.DbFunctionDetails(DatabaseSchema = "dbo")]
public IQueryable<GetDataReturnModel> GetData(long? Id)
{
var idParam = new System.Data.Entity.Core.Objects.ObjectParameter("ID", typeof(long)) { Value = Id.GetValueOrDefault() };
return ((System.Data.Entity.Infrastructure.IObjectContextAdapter)this).ObjectContext.CreateQuery<GetReturnModel>("[DbContext].[GetData](#ID)", opportunityIdParam);
}
Currently, I have to remove a dataset and then loop through the GetDataReturnedModel to populate the data from this function.
What I would like to do is recover this for each record along with the main request for data.
something like:
var data = Entities.Person
.Include("Address")
.Include(p => p.GetData(p.Id)
.ToList();
Is this possible?

EF core list of string datatype to postgresql

I am using EF core 1.1.1 & postgresql with code-first implementation.
I have a model class with member variable for List as follow.
public class user : IdentityUser
{
public int id { get; set; }
[Column("devices", TypeName = "text[]")]
public List<string> devices { get; set; };
}
I declared datatype as text[] and it shows as text array in database. Saving to database as follow works.
var device = "phone";
user.devices.Add(device);
It stores data in database but it returns an error when I try to call query like this.
if (user.Any(x => x.devices.Count > 0))
Showing error like this.
Can't cast database type _text to List`1'
How can I convert stored text data to List?
Thanks.
Late but still - use string[] instead of List<string>.
public string[] Devices { get; set; }
Bad news is that you cannot use the x => x.Devices.Count > 0 lambda anyway when querying directly from DB, since the EF+Npgsql still cannot convert these expressions into SQL (at least in versions <= 1.1.0...)
You'll have to write this condition in raw SQL.
var result = db.YourTable
.FromSql("select * from your_table where array_length(devices) > 0")
.Where(...)
.OrderBy(...)
...
.ToList();
Filtering fetched rows in memory works normally, of course.

LINQ to Entities does not recognize the method ... method, and this method cannot be translated into a store expression.

MVC 5, C# -
I am creating a view model based upon different sets of data in my database. I have the following code to create the View Model.
public ActionResult Register_step6()
{
CoreGeneral cg = new CoreGeneral();
var model = (from p in db.WorkPointRoles
select new RegisterEmployee_Step6Model()
{
Role = p.Role,
Selected = false,
RoleDescription = cg.GetRoleDescription(p.Id)
});
return View(model);
}
I receive the following error message :
LINQ to Entities does not recognize the method 'System.String
GetRoleDescription(Int32)' method, and this method cannot be
translated into a store expression.
I understand that the message has something to do with the Entities not recognising my GetRoleDescription code because it is placed in the select statement - (I've porbably worded my understanding incorrectly).. anyway, how do I solve the problem, where can I put the GetRoleDescription so that it runs on every record returned?
I hope this makes sense to someone! Apologies for the poorly worded question. Thanks in advance!
You should perform projection to RegisterEmployee_Step6Model in-memory instead of SQL Server side.
public ActionResult Register_step6()
{
CoreGeneral cg = new CoreGeneral();
var model = (from p in db.WorkPointRoles
select p).AsEnumerable()
.Select(r => new RegisterEmployee_Step6Model()
{
Role = r.Role,
Selected = false,
RoleDescription = cg.GetRoleDescription(r.Id)
});
return View(model);
}

Categories