linq to sql OnLoaded() with SQL View? - linq

I am trying to extend my Linq-to-Sql entity with a few extra properties. These are "calculated" properties based on data from the underlying SQL View. For example, think of having a Date of Birth field, which is used to calculate an extended Age field.
I tried to extend my entity class by extending the OnLoaded() method.
I get a compile time error however stating that I cannot create it. I checked the designer code for my LTS entity class, and it doesn't have a partial definition for any of the expected extension points.
I checked a few of my other LTS entity classes and they do have these extension points. The only difference I see is that the one without is loaded from a SQL View, rather than a table. Is there a way to hook into a "Loaded" event when loading from a SQL View?
TIA!

I found that I did not have a PrimaryKey specified for my Linq-to-Sql entity class. I believe without a Primary Key specified, no extension methods generated in the entity class. Once I specified a Primary Key on my LTS entity class definition (through the designer), I was able to extend the OnLoaded() event.

You can do this by means of a property. Just create a partial class with the same name as your entity. Any properties or methods that you add will automatically be part of the entity and allow to use any of its members.
Here's an example of the pattern:
public partial class [The Name of the Entity]
{
public int Age
{
get
{
return CalculateAge(this.DateOfBirth);
}
}
}
Here's some logic on how to calculate the Age (Source: Geekpedia)
public static int CalculateAge(DateTime BirthDate)
{
int YearsPassed = DateTime.Now.Year - BirthDate.Year;
// Are we before the birth date this year? If so subtract one year from the mix
if (DateTime.Now.Month < BirthDate.Month ||
(DateTime.Now.Month == BirthDate.Month && DateTime.Now.Day < BirthDate.Day))
{
YearsPassed--;
}
return YearsPassed;
}

Related

How can I delete all records from a table?

I've been searching for an answer on how to delete ALL records from a table using LINQ method syntax but all answers do it based on an attribute.
I want to delete every single record from the databse.
The table looks like so:
public class Inventory
{
public int InventoryId { get; set; }
public string InventoryName { get; set; }
}
I'm not looking to delete records based on a specific name or id.
I want to delete ALL recods.
LINQ method syntax isn't a must, bt I do prefer it since it's easier to read.
To delete all data from DB table I recommend to use SQL:
Trancate Table <tableName>
Linq is not meant to change the source. There are no LINQ methods to delete or update any element from your input.
The only method to change you input, is to select the (identifiers of the )data that you want to delete in some collection, and then delete the items one by one in a foreach. It might be that your interface with the source collection already has a DeleteRange, in that case you don't have to do the foreach.
Alas you didn't mention what your table was: Is it a System.Data.DataTable? Or maybe an Entity Framework DbSet<...>? Any other commonly used class that represents a Table?
If you table class is a System.Data.DataTable, or implements ICollection, it should have a method Clear.
If your tabls is an entity framework DbSet<...>, then it depends on your Provider (the database management system that you use) whether you can use `Clear'. Usually you need to do the following:
using (var dbContext = new MyDbContext(...))
{
List<...> itemsToDelete = dbContext.MyTable.Where(...).ToList();
dbContext.MyTable.RemoveRange(itemsToDelete);
dbContext.SaveChanges();
}

Map extra column from stored procedure to Entity Framework code first model

I am using Entity Framework code first with a generic repository pattern with ASP.NET MVC. I have two tables Category and Product.
My model class of product is like this
Public class Product
{
public int ProductID{get;set;}
Public int CategoryID{get;set;}
[ForeignKey("CategoryID")]
public virtual Category Category{get;set;}
[NotMapped]
public string CategoryName{get;set;}
}
The model is binding correctly as long as I am getting data using DBContext.
But I am having a problem when I am getting list of products from stored procedure mapped to Product object. So it is not mapping the Category property of Product object and hence I cannot able to get Category.CategoryName.
So I added a new property with [NotMapped] attribute in product class as CategoryName. But it is also not binding from stored procedure.
And if I remove the [NotMapped] attribute then it is correctly binding from stored procedure but error occurs again when getting product by DbContext (Linq).
Please help me in this regards.
You don't need to add an extra property, use the DbSet.SqlQuery method for queries that return entity types. The returned objects must be of the type expected by the DbSet object, and they are automatically tracked by the database context unless you turn tracking off.
var products= _context.Products.SqlQuery("storedProcedureName",params);
The columns returned by SP should match the properties of your entity type otherwise, it will throw an exception.
After execute your SP, you should be able of get the CategoryName through your Category navigation property:
var catName=someProduct.Category.CategoryName;
On the other hand, the returned data by the Database.SqlQuery isn't tracked by the database context, even if you use this method to retrieve entity types. If you want to track the entities that you get after execute your SP using this method, you can try this:
//Attach the entity to the DbContext
_context.Product.Attach(someProduct);
//The Category navigation property will be lazy loaded
var catName=someProduct.Category.CategoryName;
If you have disabled lazy loading you can load explicitly your navigation property:
//Load the Category navigation property explicitly
_context.Entry(someProduct).Reference(c => c.Category).Load();

ASP.Net WebAPI IIQueryable covert to POCO Objects

I have been using the WebAPI in ASP.Net to allow access to our Entity Framework Objects.
The problem I am having is converting the objects to a custom POCO for our end customers to use.
I need to convert the Entity Framework Object to a custom POCO.
For example in our SQL Database we have Tbl_Person with the following properties
PersonID
FirstName
SureName
DateOFBirth
AnnualSalary
This table maps to an Entity Framework class Person with the same properties.
But I want to change the properties so that when a end customer accesses it they get a POCO like:
PersonID
Name
Age
SalaryRange
I also want to keep the current features such as JSON & XMLoutput and allow for OData queries.
I have been trying to 'Collect' the Odata Query and applyto my database context but this does not seem to be work correctly
Please see code example below:
Imports System.Net
Imports System.Web.Http
Imports System.Data.Entity
Public Class PeopleData
Inherits DbContext
Public Property People() As DbSet(Of Person)
End Class
Public Class Person
Public Property PersonID() As Integer
Public Property FirstName() As String
Public Property SureName() As String
Public Property DateOFBirth() As Date
Public Property AnnualSalary() As Integer
End Class
Public Class PeopleController
Inherits System.Web.Http.ApiController
Private db As New PeopleData
Function GetPeople(query As OData.Query.ODataQueryOptions(Of Person)) As IQueryable(Of apiPerson)
Dim pep = query.ApplyTo(db.People)
Dim resPep As New List(Of apiPerson)
For Each p In pep
resPep.Add(New apiPerson(p))
Next
Return resPep.AsQueryable
End Function
End Class
Public Class apiPerson
Public Sub New(ByVal p As Person)
PersonID = p.PersonID
Name = p.FirstName & " " & p.SureName
Age = Date.Now.Year - p.DateOFBirth.Year
If p.AnnualSalary > 15000 Then
SalaryRange = "High"
Else
SalaryRange = "Low"
End If
End Sub
Public Property PersonID() As Integer
Public Property Name() As String
Public Property Age() As Integer
Public Property SalaryRange() As String
End Class
I have two problems:
1) The API help pages don't populate and only produce this error: 'Sample not available.'
I like the dynamic help pages & that they pick up code comments, this is a really quick and easy way to maintain documentation. How can I get them to work with the ApiPerson?
2) If I try /api/people?$filter=Age eq 29 I get an error Type 'MvcApiPeople.Person' does not have a property 'Age'.
I understand that the LINQ Query is been passed to the 'Person' and that property does not exist but how can I 'Translate' queries to map to different properties in the actual Database Object?
Your action declaration should be
Function GetPeople(query As OData.Query.ODataQueryOptions(Of apiPerson)) As IQueryable(Of apiPerson)
i.e query parameter should be of type ODataQueryOptions (Of apiPerson) not ODataQueryOptions (Of Person).
Regarding your question 1:
I think your problem is that the apiPerson-class is missing a parameterless constructor.
Also, I found a blog post with some information on how to customize sample generation when the default generation mechanism doesn't work:
http://blogs.msdn.com/b/yaohuang1/archive/2012/10/13/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help-page.aspx.
After playing around with many different solutions I decided the simplest way to control the information that is made available on an API and still allow iQueryable is to control the data at database level or at class level with Data Contract annotations.
I actually created views in my database to render the data exactly how I want it to appear for end customers. I felt this had the best benefits for performance and speed of implementation.
Thank you to all the guys who offered suggestions.

Programmatically Change Database Table EntityFramework Model Object Refers to

Question is in the title. Can we programmatically change the database table which an object in the Model class, like one below, refers to and continue to operate on the new table?
public class Word
{
public int ID { get; set; }
public string Text { get; set; }
}
This originally refers to "Words" table automatically in EntityFramework, is there a way to change it before/during runtime? If so, how?
EDIT:
I get all the string used in Views in the project from the database table, "Words", by their ID's. Now, what I want is, a user enters a new language to system, and a new table will be created, for example WordsEnglish. From then, the Word object will refer to WordEnglish, if user selects English as language.
It would be desirable with a use case to better understand what you are trying to accomplish, but here goes...
In the DbContext.OnModelCreating method you can configure the model, e.g.
// Removes pluralization convention for all tables.
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
or
// Specific table name for Word Entity.
modelBuilder.Entity<Word>().ToTable("TableContainingWords");
If you are changing your model, Code First Migrations might be what you need.
I havent found a way to truly dynamically extend an EF model at runtime. Given what goes on in DB context inherited class, the use of generated views for performance and a model class approach, avoiding recompilation seems hard. I have generated code, compiled and access this using assembly discovery approaches. But this is all unsatisfactory from my viewpoint , so i have stopped investigating this path. Very clunky outcome.
Ironically the topic you provide as a use case for such a problem, is one that doesnt need dynamic EF in my view.
I have exactly the same use case, language specific look for messages/labels etc Ie a language specific textpool.
Why not add language to the class/table.
Use a table or Enum for supported languages.
Use Language in the Textpool table/s
Use a different model class for presentation. (view model).
So you can present it the way like .
public class Word
{
Guid ID {get;set;} // logical key is WordID + Language
public int WordID { get; set; } // implement with new id or 2 field key
public Language Language {get;set;} // see cultureInfo for more details
public bool IsMaster {get;set;}
public string Text { get; set; } // consider renaming due to reserved word implications
}
public class language
{
int ID,
String Lang
}
}

DevExpress XtraReport data binding for object attributes

I have an report, in which I like to show reports about some Employees. The Employee Class contains the following attributes :
public class Employee {
public string name;
public Branch branch;
}
I have an list of employees, and I bind them to the report columns. It is showing employee name without any problem in the first column of the report table, but in the second column it is showing the Branch object's assembly, namespace etc etc. (It is obvious, of course, since I am binding the whole Branch object to that column).
My question is : how can I show employee name in one column and corresponding branch name in another column?
My Branch Class has the following definition :
public class Branch{
public int branchId;
public string name;
}
I am adding an data source to the report class from the tool box, creating an XtraReport object, and simply assigning an Employee list as follows :
XtraReport1.DataSource = EmployeeList;
XtraReport objects can do sub-property binding. Give your label the text "[branch.name]" (rather than picking the data source with the designer drop-down).
your binding probably looks like:
....DataBindings.Add(new Binding("Text", employee, "branch"));
change it to
....DataBindings.Add(new Binding("Text", employee.branch, "name"));

Resources