how to avoid creating entities for returning small data from database - c#-3.0

Oftentimes I need to return a list of two or three columns from a stored proc in the data layer. I usually use entities to push data back to the business/UI layer. However, I don't want to create an entity for something that is not really an entity.
Lets say I have to return a set of "date, string, string", is there any other way to do this.. for two columns, i can perhaps get away with a dictionary. I always end up creating a dummy entity but thought I'll ask this time.

Create a new model to store the data:
public class ResultModel
{
public DateTime DateTime1 { get; set; }
public string String1 { get; set; }
public string String1 { get; set; }
}
then just store your data into this like so:
IEnumerable<ResultModel> results =
Entities.Table.Select(r => new ResultModel
{
DateTime1 = r.DateTime,
String1 = r.String1,
String2 = r.String2
});
Not verified the code but is a guide as to how to achieve this.

You could probably use a Tuple for this kind of data however I've never found any real detriment to creating more understandable types, even for simple data.

Related

How to explicitly set the ID property on an autoincrementing table in EFCore

I have a model which has an auto-incrementing ID field by default as is normal. However, I wish to seed the database with initial data and because there are foreign keys I wish to explicitly set the IDs of the seeded data.
My model
public class EntAttribute
{
public int ID { get; set; }
public string Title { get; set; }
}
My seeding code:
public class Seeder
{
private class AllAttributes
{
public List<EntAttribute> Attributes { get; set; }
}
public bool SeedData()
{
AllAttributes seedAttributes;
string strSource;
JsonSerializer JsonSer = new JsonSerializer();
strSource = System.IO.File.ReadAllText(#"Data/SeedData/Attributes.json");
seedAttributes = JsonConvert.DeserializeObject<AllAttributes>(strSource);
_context.AddRange(seedAttributes.Attributes);
_context.SaveChanges();
return true;
}
}
Please note, I'm very new to both EFCore and C#. The above is what I've managed to cobble together and it seems to work right up until I save the changes. At this point I get:
SqlException: Cannot insert explicit value for identity column in table 'Attribute' when IDENTITY_INSERT is set to OFF.
Now I'm smart enough to know that this is because I can't explicitly set the ID field in the EntAttribute table because it wants to assign its own via auto-increment. But I'm not smart enough to know what to do about it.
Any help appreciated.
EDIT: Adding the solution based on the accepted answer below because the actual code might help others...
So I added to my Context class the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("EntAttributeNumbering")
.StartsAt(10);
modelBuilder.Entity<EntAttribute>()
.Property(i => i.ID)
.HasDefaultValueSql("NEXT VALUE FOR EntAttributeNumbering");
}
This first ensures the a sequence is created (the name is arbitrary) and then secondly, sets it to be used for the relevant table instead of auto-increment. Once this was done I was able to my seed data. There are fewer than 10 records so I only needed to set the start value for the sequence to 10. More would normally make sense but I know there will never be more.
I also had to blitz my migrations because they'd somehow got in a mess but that's probably unrelated.
With EF Core you can create and use a Sequence object to assign the IDs, and you can reserve a range of IDs for manual assignment by picking where the sequence starts. With a Sequence you can assign the IDs yourself, or let the database do it for you.
FYI for people using EF Core 3, if using int for your key you can set the start sequence value incase you have seeded data. I found this a much cleaner to solve this problem in my use case which just had a single seeded record.
e.g
modelBuilder.Entity<TableA>()
.Property(p => p.TableAId)
.HasIdentityOptions(startValue: 2);
modelBuilder.Entity<TableA>()
.HasData(
new TableA
{
TableAId = 1,
Data = "something"
});
https://github.com/npgsql/efcore.pg/issues/367#issuecomment-602111259

Simple contract for use with FromSql()

With its recent improvements, I'm looking to move from Dapper back to EF (Core).
The majority of our code currently uses the standard patterns of mapping entities to tables, however we'd also like to be able to make simple ad-hoc queries that map to a simple POCO.
For example, say I have a SQL statement which returns a result set of strings. I created a class as follows...
public class SimpleStringDTO
{
public string Result { get; set; }
}
.. and called it as such.
public DbSet<SimpleStringDTO> SingleStringResults { get; set; }
public IQueryable<SimpleStringDTO> Names()
{
var sql = $"select name [result] from names";
var result = this.SingleStringResults.FromSql(sql);
return result;
}
My thoughts are that I could use the same DBSet and POCO for other simple queries to other tables.
When I execute it, EF throws an error "The entity type 'SimpleStringDTO' requires a primary key to be defined.".
Do I really need to define another field as a PK? There'll be cases where there isn't a PK defined. I just want something simple and flexible. Ideally, I'd rather not define a DBSet or POCO at all, just return the results straight to an IEnumerable<string>.
Can someone please point me towards best practises here?
While I wait for EF Core 2.1 I've ended up adding a fake key to my model
[Key]
public Guid Id { get; set; }
and then returning a fake Guid from SQL.
var sql = $"select newid(), name [result] from names";

EF Code First validating and updating objects

I am working on an N-tier application consisting of a UI layer (MVC), a Business Layer, a Domain layer (for the models) and a DAL for repositories and the EF DbContext.
I'm a bit confused about the inner workings of Entity Framework when updating the properties of an existing object and I'm looking for a good way to validate an object before updating its values in the database.
I have the following model:
public class BlogPost
{
public int BlogPostId { get; set; }
[Required]
public String Title { get; set; }
[Required]
public String Description { get; set; }
[Required]
public DateTime DateTime { get; set; }
public byte[] Image { get; set; }
}
I have the following methods in my manager in BL:
public BlogPost AddBlogPost(string title, string description, byte[] image = null)
{
BlogPost blogPost = new BlogPost()
{
Title = title,
Description = description,
DateTime = DateTime.Now
};
Validate(blogPost);
moduleRepository.CreateBlogPost(blogPost);
return blogPost;
}
public BlogPost ChangeBlogPost(BlogPost blogPost)
{
moduleRepository.UpdateBlogPost(blogPost);
return blogPost;
}
And I have the following methods in my DAL:
public BlogPost CreateBlogPost(BlogPost b)
{
b = context.BlogPosts.Add(b);
context.SaveChanges();
return b;
}
public BlogPost UpdateBlogPost(BlogPost b)
{
context.Entry(b).State = EntityState.Modified;
context.SaveChanges();
return b;
}
My question now is: what's a good way to check that the model is valid before actually trying to change its values in the database?
I was thinking something like this:
public BlogPost ChangeBlogPost(BlogPost blogPost)
{
// STEP 1: put the updated data in a new object
BlogPost updatedBlogPost = new BlogPost()
{
Title = blogPost.Title,
Description = blogPost.Description,
Image = blogPost.Image,
DateTime = blogPost.DateTime
};
// STEP 2: check if the model is valid
this.Validate(updatedBlogPost);
// STEP 3: read the existing blog post with that ID and change the properties
BlogPost b = moduleRepository.ReadBlogPost(blogPost.BlogPostId);
b.Title = blogPost.Title;
b.Description = blogPost.Description;
b.Image = blogPost.Image;
b.DateTime = blogPost.DateTime;
moduleRepository.UpdateBlogPost(blogPost);
return blogPost;
}
EDIT: I figured it's maybe better to just accept primitive types as parameter in the above method instead of the object.
I have a feeling that's too much work for a simple update, but I couldn't find anything else on the internet.
It's probably also worth noting that I'm using a singleton for the DbContext so I have to make sure Entity Framework doesn't change the values in the database before checking that those values are valid (since another call to the context by another class can cause SaveChanges()).
I know singleton on a DbContext is bad practice, but I saw no other option to avoid countless exceptions when working with multiple repositories and entities being tracked by multiple context instances.
PS: I also read about change tracking in Entity Framework but I'm not 100% sure how this will affect what I'm trying to do.
All suggestions and explanations are welcome.
Thanks in advance.
You would check ModelState.IsValid. There are a lot of validation mechanisms built into MVC that you can take advantage of. Built in attributes such as [Required] that you reference above, custom validators, making your business class implement IValidatableObject, overriding EF SaveChanges() to name a few. This article is a good start: https://msdn.microsoft.com/en-us/data/gg193959.aspx
Ok so I kinda answered my own question while doing some research and testing with some dummy data. I thought that when a property changed in MVC as a result of an Edit view, EF also tracked it and changed it in the database.
I figured out that's not how model binding works and realized after some fooling around that model binding actually creates a new object (instead of editing the properties of a dynamic proxy).
I guess I can now just validate the model and then just update the one with the same primary key in the database.

Making EntityFramework set one property first, before the others

When using code-first EntityFramework, I need one property to be set before the others - how do I specify the order that it calls the property sets, when it is creating the objects from the database?
E.g.
public class Person
{
public string Name { get; set; }
public string Something
{
get { return something; }
set
{
something = value + " for " + Name;
}
}
private string something;
}
In the code above, I need the Name property to already have been set by the time it sets the Something property.
This isn't the actual example - I know there are other ways to achieve that literally, but I'm not after those, just how I can tell EF to set Name before Something.
I am trying to understand the context of your question. I am going to make the assumptions that:
The value passed to the setter is not another calculated property
the value passed to the setter is intended to be stored in the database
If name is updated you would want Something to be updated to reflect the new name?
I think your mistake here is trying to add a derived portion to the value you are looking to store. Calculate the pretty name in another property, or on a get:
UPDATE had an example overriding the get on the Something Property, but removed as I feel it is bad practice.
public class Person
{
public string Name { get; set; }
public string Something { get; set; }
public string getFancySomething {
{ return Something + " for " + Name; }
}
}
Finally - (and here is where I could use some help as I have not run into a situation where I needed to do something like this) my guess is that you do not need to be storing the partially calculated property Something in the way you were attempting, but if you do need to, I think additional detail might help someone provide you with a better answer.
UPDATE 2
As described in my comments - not sure this would work, and it feels very wrong, but you could try something like:
modelBuilder.Entity<Person>().Ignore(x => x.Something);
and then in the setter:
public class Person
{
public string Name {
get { return Name; }
set {
Name = value;
Something = lookup();
}
}
}
Again this will depend on you needs, and would not satisfy any need to pass this value in, and I am not sure this is a great idea.

Building a flexible parameterized adhoc query with C#, SQL

I'm in the process of building the capability for a user to perform ad-hoc queries on a SQL Server database. The resulting query will take on the following basic form:
SELECT <ONE TO MANY USER SELECTED FIELDS>
FROM <ONE TO MANY TABLES DETERMINED BY FIELDS SELECTED BY USER>
WHERE <ZERO TO MANY CRITERIA FOR THE SELECTED FIELDS>
It's a guarantee that the selection will most likely span more than one table.
Some (not all) of the fields may have 0 or more filter criteria for a particular field.
My application is using the default EF4 classes within ASP.NET MVC 2 using C#. I am currently passing in an object called QueryItem that contains all the information for a particular criteria.
My question(s) are:
What is the best approach for coding this? (Code samples of what I have to date below).
Can this be done with Linq2SQL or should I use ADO.NET(My current approach)
If ADO.NET is the best way, how do you access the DBConnection within EF4?
Note: I intend to refactor this into SQLParameter objects, to protect against SQL injection. My goal right now is best practice in developing the query first.
QueryItem class:
public class QueryItem
{
public bool IsIncluded { get; set; }
public bool IsRequired { get; set; }
public string LabelText { get; set; }
public string DatabaseLoc { get; set; }
public List<string> SelectedValue { get; set; }
public List<SelectListItem> SelectList { get; set; }
}
Query Parsing Code
foreach(QueryItem qi in viewModel.StandardQueryItems)
{
string[] dLoc = qi.DatabaseLoc.Split(new Char[] { '.' }); //Split the table.fieldname value into a string array
if(qi.IsIncluded == true) //Check if the field is marked for inclusion in the final query
{
fields.Append(qi.DatabaseLoc + ","); //Append table.fieldname to SELECT statement
if(!tables.ToString().Contains(dLoc[0])) // Confirm that the table name has not already been added to the FROM statement
{
tables.Append(dLoc[0] + ","); //Append the table value to the FROM statement
}
}
if(qi.SelectedValue != null)
{
if(qi.SelectedValue.Count == 1)
{
query.Append(qi.DatabaseLoc + " = '" + qi.SelectedValue[0].ToString() + "'");
}
else
{
foreach(string s in qi.SelectedValue)
{
//Needs to handle "IN" case properly
query.Append(qi.DatabaseLoc + " IN " + qi.SelectedValue.ToString());
}
}
}
}
I have built a similar system to what you are describing in the past by passing in a single parameter to a stored procedure of type xml. By doing so, you can actually specify(in xml), what all you would like to report off of and build the SQL necessary to return the results you want.
This also makes your C# code easier, as all you have to do is generate some xml that your procedure will read. Generating Dynamic SQL is definitely not something you should use unless you have to, but when you want to allow users to dynamically select what they want to report off of, it's pretty much the only way to go about doing it.
Another option for you might be to look into Reporting Services - that will allow the user to pick what fields they want to view and save that particular 'report' in their own section where they can then go back and run it again at any time.. You could also create the reports for them if they aren't computer savvy(which is a lot easier to do with report builder, provided that all they need is data and no special features).
Either way you go about it, their are pros and cons to both solutions.. You'll have to determine which option is best for you.
xml/dynamic sql: Hard to maintain/make changes to.(I feel sorry for anyone who has to come behind someone who is generating dynamic sql and try to understand the logic behind the mess).
reporting services: very easy to spit out reports that look good, but it's a little less flexible and it's not free.