Run linq-to-sql queries on database with changing structure - c#

Is it possible to run Linq-to-SQL queries when underling database structure is changing from time to time (I mean database updates that happens due to business requirements and since database is shared among several apps It may be happens without announcements to me)?
Is there any way that I can connect to new database structure in Linq-to-SQL without updating the .dbml file in my source code?
If I want to run raw queries knowing that my database structure changes during time, can I use any of Linq-to-SQL benefits somehow?

Provided the structure you have in your classes match to your tables (at least covering all the fields you need) you can do that. ie: Northwind customers table have more than 4 fields in reality. Provided below 4 are still in that table this would work:
void Main()
{
DataContext db = new DataContext(#"server=.\SQLexpress;trusted_connection=yes;database=Northwind");
Table<Customer> Customers = db.GetTable<Customer>();
var data = Customers.Where(c => c.Country == "USA");
foreach (var customer in data)
{
Console.WriteLine($"{customer.CustomerID}, {customer.CompanyName}");
}
}
[Table(Name = "Customers")]
public class Customer
{
[Column]
public string CustomerID { get; set; }
[Column]
public string CompanyName { get; set; }
[Column]
public string ContactName { get; set; }
[Column]
public string Country { get; set; }
}
For raw SQL, again you could use a type covering fields in select list or dynamic.
Note: For inserts, for this to work, fields that are not in your model should either accept null or have default values.

Related

Entity Framework database-first approach conditionally insert data

Using Entity Framework, how can I insert data if it does not exist, and update a field if it does?
public class Rootobject
{
public string odatacontext { get; set; }
public Value[] value { get; set; }
}
public class Value
{
public int AccountId { get; set; }
public DateTime? SubmissionDate { get; set; }
public string Status { get; set; }
}
To retrieve all the data from my API I use
root.value.Select(x => new satiaL
{
accountID = x.AccountID,
subDate = x.SubmissionDate,
x_status = x.Status
});
which of course will insert all records.
If the AccountID already exists in the database, I want to update the value of x_status, but if the AccountID does NOT yet exist in the database, then I want to insert all values.
You can not.
Upsert functionality is not part of an object/relational model - objects are there or not, and tracked by identity. Thre is no "update if it is not there" concept - at all. So, there is nothing for EfCore to implement.
This smells like abusing an ORM as a ETL loader, and this is not what you should do - ETL (mass data loading) is not what and ORM is made for. Time to write your own method to move data up into tables and possibly do upswert there. Did that years ago, comes really handy at times.
Right now all you can do is run a lot of finds for every account and basicalyl write code: create if not exists, update if exists.
Pseudocode:
var account = Find ( select ) or default from db
if account == null create
else update
savechanges
Something along this line. Beware of performance - you may want to just builk load all accounts. Beware of conflicting updates.

EF & Web API 2 Multiple Round trips to the database to populate object model

It seems this problem would have been encountered before me but I'm not finding much help online probably because I don't really know what to search for.
My problem in short is that I have a db table. That table has 5 keys to other tables.
I then have a model that represents this table in EF. Of course this object that represents the db table has List<T> properties that are representations of foreign keys in the db. That doesn't seem to be the problem as much as the EF model that has this table representation but also List<T> properties to other models.
The problem I am experiencing is that a call to a stored procedure to populate the main modelforces additional calls to the db to populate the related List<T> models.
I am looking to improve performance namely by eliminating the multiple calls.
My only thought to this point is to modify the stored procedure to return multiple recordsets and match each List<T> property to its corresponding recordset.
My sterilized structure is something like this.
DB:
sql_Id Int PK
sql_Status Int FK
sql_Reason Int FK
sql_GuestId Int
sql_Name varchar
sql_Created DateTime
sql_Original Int FK
EF:
public class OrderHeader : ClassBase
{
public OrderHeader()
{
TaskCodeAssignments = new List<OrderHeaderTaskCodeAssignment>();
StatusReasonCode = new OrderHeaderStatusReasonCode();
StatusCode = new OrderHeaderStatusCode();
Links = new OrderHeaderLinks();
}
public int OrderHeaderID { get; set; }
public short OrderHeaderStatusCodeID { get; set; }
public short? OrderHeaderStatusReasonCodeID { get; set; }
public short? OriginatingApplicationId { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public OrderHeaderStatusCode StatusCode { get; set; }
public OrderHeaderStatusReasonCode StatusReasonCode { get; set; }
public CustomerStatusCode CustomerStatusCode { get; set; }
public ICollection<OrderHeaderTaskCodeAssignment> TaskCodeAssignments { get; set; }
}
public class OrderHeaderStatusCode
{
public OrderHeaderStatusCode()
{
OrderHeaderStatusReasonCodes = new List<OrderHeaderStatusReasonCode>();
}
public ICollection<OrderHeaderStatusReasonCode> OrderHeaderStatusReasonCodes { get; set; }
public virtual ICollection<OrderHeader> OrderHeader { get; set; }
}
The other custom types like OrderHeaderStatusReasonCode are pretty similar in design so I'm leaving out for brevity.
C# Web API
public async Task<IHttpActionResult>GetOrdersHistory([FromUri]GetOrderRequestParameters orderParams)
{
....removed for brevity....
var query = await TheOrderRepository.GetOrderHistory(getOrder);
}
Order Repository:
public async Task<IQueryable<OrderHeader>> GetOrderHistory(GetOrderParameters orderParams)
{
// this is the call to stored procedure that I would modify to return multiple recordsets
var storedProcedure = StoredProcedure.Name.MyStoredProc.ToString();
var ordersHistory = await dbctx.Database.SqlQuery<OrderHeader>(...), storedProcParam).ToListAsync();
// now I jump off to fill in the other properties and their data has to come from the db
await GetOrdersData(ordersHistory, orderParams.Include);
}
private async Task GetOrdersData(List<OrderHeader> ordersHistory)
{
if (ordersHistory != null)
{
await LoadOrderStatusCodeForList(ordersHistory);
await LoadOrderStatusReasonCodeForList(ordersHistory);
await LoadCustomerStatusCodeForList(ordersHistory);
await LoadOrderHeaderTaskCodeAssignmentsForList(ordersHistory);
await LoadOrderHeaderTaskCodeForList(ordersHistory);
}
}
Again most of these awaits are similar so I'm just going to give an example of one...
private async Task LoadOrderStatusCodeForList()
{
....snipped for brevity...
await LoadOrderStatusCode(order.OrderHeaderStatusCodeID));
}
private async Task<OrderHeaderStatusCode> LoadOrderStatusCode(short orderHeaderStatusCodeId)
{
....snipped brevity....
var storedProcedure = StoredProcedure.Name.MySprocStatusCode.ToString();
return await _dbctx.Database.SqlQuery<OrderHeaderStatusCode>(...), ...).FirstOrDefaultAsync();
}
EDIT:
The crux is this. OrderHeader has properties with a custom type and basically those custom types have a List<T> that has to be populated. My current design is such that I repeatedly hit the db to populate those custom types List properties.
Is there a way to make one trip to the db to get all my information. As mentioned earlier the only way I can think of is to modify the stored procedure to return multiple record sets and then match them up.
BTW the architecture may be the flaw...in which case educate me on how to properly populate a complex object like this.
TIA
The root problem is that stored procedures aren't composable. In SQL you can't join a stored procedure call with anything (a database table or another stored procedure). So EF can't do that either.
If you want to get data with loaded collections from the database, normally you'd have to use Includes. EF will translate that into the appropriate joins and figure out how to load the entities and their collections from one big result set. But, as said, joins are no option here.
There is a way to load multiple result sets from one stored procedure. IMO it's pretty messy and very procedural. I would keep loading the data separately as you do now, if you want to keep using stored procedures. Others may suggest that you could load the additional data by lazy loading. Unfortunately that's not as straightforward as it should be with SqlQuery.
Another option of course is to start using regular DbSets (with Includes), but I can't judge if that's possible for you.

Dynamic CRUD against unknown/multiple MSSQL databases

I would like to get some ideas about how retrieve data from a MSSQL database with the constraints for all the columns. I'm listing all the databases on a server, and let the user choose the database, and after that, let them choose a table to CRUD against. This is going to be shown in a javascript grid (Slickgrid) for inline editing.
It's going to be very close to what you get when you rightclick a table in MSSQL Management Studio and select Edit top 200
Chalenges:
The application should access a bunch of different databases that often change, so generating POCOs is out of the question. The databases are also very often porly made and does not contain FKs as they should.
I do need to have some server side validation, and preferably client side as well for all the columns, so I do need to get the information about datatype, nvarchar length, nullable or not and so on from the DB.
I'm used to program in C# with EF/ADO.NET, but i would not mind trying some other languages like Node.js, if there are any good support for what I'm after (Not interested in PHP though).
I was thinking about using ASP.NET MVC with ADO.NET and read the data into some models like this:
public class GridVM
{
public IEnumerable<Column> ColumnDefinitions { get; set; }
public IEnumerable<dynamic> Rows { get; set; }
}
public class Column
{
public string Name { get; set; }
public string Type { get; set; } //perhaps public Type Type?
public bool Nullable { get; set; }
public int MaxLength { get; set; }
}
And then creating a list of dynamics with the number of properties corresponding with the number of entries in the ColumnDefinitions.
dynamic
{
public object column1 { get; set; }
public object column2 { get; set; }
public object column3 { get; set; }
//etc, so that I get properties for all the columns
}
I do have some code for binding retrieved data from a DataReader to a data model, ignoring the property names not corresponding with the column names, but I need to do it without having a known data model.
The questions:
Is this a good approach or should i reconsider using some other technique or method? Are there any pitfalls with this approach that I'm not seeing right now?

ASP.Net - Create Entity Class From Query Fields - Visual Studio

I am very new to ASP.Net and MVC applications so pardon me if this question has been asked or is trivial.
I know how to create an entity model class from a database table, but I want to perform a series of Joins and create a Pivot table from an SQL query and then pass this to a view.
However, I do not know a quick way to create an entity class for this.
Currently, I am doing it the long way by manually defining a model class like so:
public class OAData
{
public int Zone { get; set; }
public string Device { get; set; }
public string Part { get; set; }
...
//CONSTRUCTOR
public OAData(int zone, string device, string part...){
Zone = zone;
Device = device;
Part = part;
...
}
}
and then create a database connection in the controller, loop through all the records, creating OAData objects for each record, add it to a list and then pass that list to the View.
Is there an easier way to do this (there are many fields returned by the query)? Can I create a model from a complex SQL query rather than just off a database table?

Restrict Operations On Database Through Repository

I have implemented Unit of Work and Repository pattern with Entity Framework. A sample operation is shown below:
public T GetById(int id)
{
return _context.Set<T>().Find(id);
}
So if I wanted to bring a record with id 12 and only StudentName column. I cannot do that using the above method as all columns will be pulled which I could have done using Linq like below:
Student get = context.Students
.Where(s => s.Id = 12)
.Select(s => new { StudentName = Name })
.SingleOrDefault();
Currently, I am returning an IQueryable from the repository like below to make above aforementioned scenario work:
public IQueryable<T> Query()
{
IQueryable<T> query = dbset;
return query;
}
which makes the point of having a Repository to null anyway because I cannot restrict operations on database now. I have to query like below:
Student get = _uow.Students
.Query()
.Where(s => s.Id = 12)
.Select(s => new { StudentName = Name })
.SingleOrDefault();
Any suggestions on how to improve this situation or other opinions are required please.
I would argue that you are worried about restricting operations at the wrong layer; the Repository. Assuming your Repositories are supposed to abstract away the details of your DB and Entity Framework, I think this is too low of a level to do what you want.
If you have a Repo per DB table, and a class per query result type (direct SQL/EF or DB View), it doesn't make sense to introduce another layer of abstraction here. It would be better to do this at the next layer up, or whatever is handling your transactional boundaries.
To demonstrate, here is a more concrete example:
Given a Student DB table:
TABLE Student
PK Id int
COLUMN Name string
COLUMN SecretData string
Your StudentRepo should always return instance(s) of a Student class:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string SecretData { get; set; }
}
Then the layer that utilizes your repo(s) should handle your transactions (potentially across multiple repos/operations) and map its results to a Domain entity. Your domain entity can include only the fields which you want to surface. You can create specialized domain entites for each purpose you need.
public class DomainStudent
{
public int Id { get; private set; } // prevent attempts to change Ids on domain entities
public string Name { get; set; }
}
public class DomainStudentWithSecret
{
public int Id { get; private set; }
public string Name { get; set; }
public string SecretData { get; set; }
}
And to expand on why you would want to handle this kind of mapping and transactional boundaries outside of your Repository code: these things are best left to code which can operate across many DB tables. Often you need to take the result of two separate SQL queries and map the result to a single domain entity. Or sometimes, you want to roll back a transaction (or not execute subsequent SQL) if an initial query fails. I find it best to keep the Repos/DAOs working on a single table/view/sproc (DB entity) to abstract away the details of the Db engine and have domain-layer classes handle the heavy lifting of how to make sense of the data. If you need complex SQL queries with many JOINs, consider creating a view so you can work with the data like any other table.

Categories