How to transfer data when using LINQ as DAL? - linq

I'm creating my first linq based project. The DAL consists of LinqToSQL classes. And the logic layer is just another DLL for keeping it simple.
I wanted to know how do I pass the var object (result of select query) from Login Layer to Presentation Layer?
Should I write my own DTO layer between Login layer and Presentation Layer to transfer the from BLL to Presentation layer or should I serialize the data as XML?
Thanks, Vikas

I would avoid serializing whenever you have the opportunity to just pass the data as a strongly typed class. And that is what you're going to have to do. I believe when .Net 4.0 comes out you will be able to pass vars, but until then, try returning your query as an IEnumerable instead of a var when you need to pass it to another function.
IE:
public class myClass
{
public int RecordID { get; set; }
public string Field1 { get; set; }
}
public void GetDataAndSendToOtherLayer()
{
using (DBDataContext db = new DBDataContext)
{
IEnumerable<myClass> Recs =
from tab in db.table
select new myClass
{
RecordID = tab.RecordID,
Field1 = tab.Field1
};
OtherLayer.DoSomething(Recs);
}
}

Load each row result into an object, place the each object into a Collection and then pass the Collection from the DAL to your BOL where it can then be handled by your business rules before the Collection is passed on to your presentation.

Related

Writing a class that models a stored procedure for consumption by Dapper

I've followed the example on http://blog.vijay.name/2012/07/dapper-micro-orm-for-oracle-and-microsoft-net/ to implement Dapper with some of my existing Oracle stored procedures. However, I am a little bit unhappy with the example, because of this block:
using ( var multi = cnn.QueryMultiple( "PKG_USERS.GetUserDetailsForID", param: p, commandType: CommandType.StoredProcedure ) )
{
u = multi.Read<User>( ).Single( );
u.Roles = multi.Read<UserRole>.ToList( );
}
Sure, this logic is easy enough to follow, but what if I have 1000 of these to implement?
I would like to be able to define a class (model) per stored procedure, then execute it using some context (which includes an IDbConnection) according to the following convention:
Each property of the model is a parameter of the stored proceudre
Each output parameter of the stored procedure is mapped to the appropriate parameter of the model by the rule name = name.
So my model would look something like this:
public class ConcreteSPModel : AbsSPModel
{
public string ParamOne { get; set; }
public string ParamTwo { get; set; }
//Attributes or other markup to indicate that this is an output parameter
public List<OtherModel> ParamThree { get; set; }
}
and I would fill it up by:
var params = new OracleDynamicParameters(myConcrete);
using (var m = Connection.QueryMultiple(myConcrete.CommandText(), param: params, commandType: myConcrete.CommandType())
{
myConcrete.FillWith(m);
// OR...
this.FillModel(myConcrete, m);
}
I've implemented something like this before without Dapper, using reflection, but before I go down that path I would like to know if there is anything built into Dapper that could enable me to avoid writing my own code to iterate over the public properties and assign each one by invoking the Read method for its generic argument and generic type?
It sounds like you aren't committed to dapper yet. If so...
Take a look at Insight.Database. It supports Oracle, stored procs, multiple recordsets, deep result structures, and more.
You can bind to a proc just by defining an interface on a method.
http://github.com/jonwagner/Insight.Database

Can I add a derived property to an EF entity and have it available to breeze?

I am using code first with an existing database, EF5, Web API and Breeze and I havent used any of these techs before. I am writing my own pocos.
I am trying to expose a read only property that requires several table joins to obtain the data. If we were using Web API only, we could just run some sql, populate the property and send some JSON back to the client.
Because we are using EF and breeze this obviously changes quite alot.
For example:
public class Employee
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public string FooBar
{
get { return getFooBar(); }
}
}
private string getFooBar()
{
// Do stuff here
}
This will send FooBar back to the client in the JSON result but because it is not mapped, and consequently not in the Metadata, I dont seem to be able to use it within Breeze.
I have read articles that say I can do this when using designer based methods (ie edit the edmx file) but how can it be done using code first?
I am aware that I can extend a Breeze entity on the client side but Im not really sure how I would get this value which hasnt been mapped, after Breeze has created all of the entities.
What I really want is to extend my code first entity. I also vaguely understand that this might not be in line with EF ideals but I also struggle with the idea that I dont have the freedom to define what is and what isnt a property of my employee.
I dont need to track changes. I dont need to save. I dont seem to be able the use the EF context provider to join the (many) tables and get the data because the entities for each table dont share a primary key and dont inherit from the same class.
I think this SO post here suggests something similar but once again its for generated classes. Is there a way to do this? Thanks.
Edit
In reply to Wards suggestion I tried a few tests.
My client side constructor:
function Employee() {
this.DisplayName = ""; // unmapped property
};
My Controller:
function TestController($scope, $routeParams) {
var manager = new breeze.EntityManager('breeze/employees');
var metadataStore = manager.metadataStore;
metadataStore.registerEntityTypeCtor("Employee", Employee);
var query = new breeze.EntityQuery()
.from("Employees")
.orderBy("FirstName");
manager.executeQuery(query).then(function (data) {
// Check unmapped property name
var employeeType = metadataStore.getEntityType("Employee");
var unmapped = employeeType.unmappedProperties;
alert(unmapped[0].name) // Returns 'DisplayName'
alert(employeeType.dataProperties[3].name) // Returns 'DisplayName'
var prop = manager.metadataStore.getEntityType('Employee').getProperty('DisplayName');
alert(prop.name) // Returns 'DisplayName'
var first = data.results[0]
var fullName = first.DisplayName
alert(fullName) // Returns empty string
$scope.employees = data.results;
$scope.$apply();
}).fail(function (e) {
alert(e);
});
};
My Angular:
<div>
<ul>
<li data-ng-repeat="employee in employees">
{{employee.DisplayName}}
</li>
</ul>
</div>
So the property seems to be setup correctly as an unmapped property, but it only returns the empty string. If I change
this.DisplayName = ""; // unmapped property
to
this.DisplayName = "Foo"; // unmapped property
then DisplayName always contains "Foo". The values from the payload are not being applied to DisplayName.
Am I missing something?
It's pretty easy on the Breeze client as explained in the Extending Entities documentation topic: you define an unmapped property in a custom constructor and register that constructor.
var metadataStore = myEntityManager.metadataStore;
metadataStore .registerEntityTypeCtor("Employee", Employee);
function Employee ()
this.FooBar = ""; // unmapped property
};
Now the Breeze metadata includes a definition of the FooBar unmapped property. The server will send a value for FooBar to the client and Breeze will populate that client Employee entity (unmapped) property when it materializes Employee entities from a query.
How you obtain that FooBar property value on the server is up to you. I don't know enough about your app. What you've shown us is a perfectly valid Code First entity definition.
Maybe you're asking an Entity Framework question rather than a Breeze question.
One way to get this working has been discussed in this SO answer from CassidyK. Here is the code snippet.
proto.initializeFrom = function (rawEntity) {
// HACK:
// copy unmapped properties from newly created client entity to the rawEntity.
// This is so that we don't lose them when we update from the rawEntity to the target.
// Something that will occur immediately after this method completes.
var that = this;
this.entityType.unmappedProperties.forEach(function(prop) {
var propName = prop.name;
that[propName] = rawEntity[propName]; // CassidyK
//rawEntity[propName] = that[propName]; // Breeze
});
if (!this._backingStore) {
this._backingStore = { };
}
};
I dont know what the side effects of this are. Perhaps one of the Breeze devs can better explain.
It seems this is only a problem when Breeze is configured for Angular.
IE
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);

Associating entities, not creating, with many-to-many relationships in EF Code First MVC3

In MVC3 Code First EF how do you associate one entity with another without creating a new one (many-to-many)?
So I have a many-to-many relationship between class1 and class2. I need class1 to hold many class2 and vice versa. However, class2 is independent; I have a list of them that I want to edit separately and then associate with a new class1.
When I pass my class2List to the controller( via AJAX and JSON), I checked and all the Ids of the class2s correspond to existing ids in the db, i.e. new class2s are not created.
Model
class
{
[key]
public int Id {set; get;}
}
class1 : class
{
private ICollection<class2> _class2s;
public virtual ICollection<class2> class2s
{
get { return _class2s ?? ( _class2s = new HashSet<class2>()); }
set { _class2s = value; }
}
}
class2 : class
{
private ICollection<class1> _class1s;
public virtual ICollection<class1> class1s
{
get { return _class1s ?? ( _class1s = new HashSet<class1>()); }
set { _class1s = value; }
}
}
Controller
public ActionResult SaveChanges(List<class2> class2List)
{
createNewClass2AndAssociateExistingClass2s(class2List);
SaveChangesToDb();
return View("ProductDetail", Model);
}
createNewClass2AndAssociateExistingClass2s(List<class2> class2List)
{
var newClass1 = newClass1()
{
class2s = class2List;
}
////UnitOfWork allows me to access several DbSets in one transaction
unitOfWork.Create(newClass1)
}
SaveChangesToDb()
{
unitOfWork.Commit();
}
What this does is create a new class1 (as it should) but instead of associating the existing class2s with it, it makes new class2s with new Ids and adds them to the database.
My question:
Does this have to do with how EF is reading my Id property from base class?
How would I be able to associate several existing class2s as a list with a new class1, without creating new class2s in the database?
Cheers
Ok so two things I learned from figuring this out:
I was inheriting from an abstract class when I should have been implementing an interface. This is a great idea if you have several entities that have a similar property such as "Id" and you want to do something like
T FindById<T>(int id) where T : IEntity
When making associations in EF, even if the Id matches an existing entry, it will not update that entry, unless EF is tracking that entry in the context, as it says here. What I needed to do was:
Add a method in the mapping layer that gets the entry by id that I
want from the repository
Copy the attributes of the new entry into that context entry
Return the context entry
Hope this helps someone

ASP.NET MVC 3 multiple Models to single Form using DB

I have a question.
My question actually extends from this one:
Shortly - what I want to get: 3 models, and 1 super model for this specific view. This super model fills(properly) IENumerable, IENumerable, IENumerable, to use them in View part. (as far as I understand it, at least...)
In this other topic Dan Revell proposed verry nice and elegant solution, but this solution does not fetch data from DB itself...
Question:
What must be done to get data in this model from DB, not from "new" instance constructors?
While using this approach tried to fetch data from DBContext. And got some problems in it ) I can't understand when (or how) to create my DBContext... Or how to access one that is created by application...
Tried to create it forcefully in Controller, like
using (var Db = new thetaskermvc.Models.TaskerDBContext())
{
var themodel = new thetaskermvc.Models.TotalView();
//Jobbers
themodel.Jobberz = new Dictionary<int, thetaskermvc.Models.Jobbers>();
var jobbers = from Jobbers in Db.Jobbers.OrderBy(g => g.jobb_name) select Jobbers;
foreach (Models.Jobbers ad in jobbers)
{
themodel.Jobberz.Add(ad.jobb_id,
new Models.Jobbers(ad.jobb_id, ad.jobb_name, ad.jobb_from, ad.jobb_carma, ad.jobb_status, ad.jobb_balance, ad.jobb_time));
}
if (themodel.Jobberz.Count == 0)
{
themodel.Jobberz.Add(-1, new Models.Jobbers(0, "NOTHING FOUND",DateTime.Now,0,"",0,0));
}
}
But as created that way Context stops it's existence (?) after passing data away from controller - I can't use it any other way but to get all data inside this controller, and fill data in model by direct add into collections in it (while use of IENumerable would fetch data on-demand, as far as I get it).
So.. If it ain't hard please enlighten me about - is it Ok to use such approach, or there is some other "common" way? Becaus beside it's clumsiness - this approach works...
PS I'm quite new to Asp, yet...
I have one view model per view with data from multiple tables (if required). On my view I have data that needs to be loaded from 2 different database tables. In my grant application controller I have the following:
private readonly IBankService bankService;
private readonly IAccountTypeService accountTypeService;
public GrantApplicationController(IBankService bankService, IAccountTypeService accountTypeService)
{
// Check incoming parameters for null values
this.bankService = bankService;
this.accountTypeService = accountTypeService;
}
In my Create action method I populate my banks and account types (to be used in drop downs) like this (different tables):
public ActionResult Create()
{
GrantApplicationCreateViewModel viewModel = new GrantApplicationCreateViewModel
{
Banks = bankService.FindAll(),
AccountTypes = accountTypeService.FindAll()
}
// Do what ever else you need to get done
return View(viewModel);
}
My partial view model would like this:
public class GrantApplicationCreateViewModel
{
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
// Other properties
}
In my repository class I would use the database context like this (I use Entity Framework code first):
public class BankRepository : IBankRepository
{
HefContext db = new HefContext
public IEnumerable<Bank> FindAll()
{
return db.Banks.OrderBy(x => x.Name);
}
}
In my database context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
}
Doing it this way you can have one view model that has data from multiple sources. I hope this answers your question? If you need more explanation please let me know :)
You may want to have a look at this post, it explains (with a sample project) how an ideal MVC application architecture should be.
In your code sample above, your shouldn't have any references to DbContexts in a controller. Controller's job is to control the flow of requests not to connect to the DB and perform Model population.

InsertOnSubmit with interfaces (LINQ to SQL)

In our code we have:
public interface ILogMagazine
{
string Text { get; set; }
DateTime DateAndTime { get; set; }
string DetailMessage { get; set; }
}
SimpleDataContext: DataContext
{
public Table<ILogMagazine> LogMagaines
{
get { return GetTable<ILogMagazine>(); }
}
}
We try to:
DataContext db = new SimpleDataContext("...");
ILogMagazine lg = new LogMagazine()
{
Text = "test",
DateAndTime = DateTime.Now,
DetailMessage = "test",
};
db.LogMagazines.InsertOnSubmit(lg); // Exception thrown
db.SubmitChanges();
Exception: System.InvalidOperationException: The type 'DataLayer.ILogMagazine' is not mapped as a Table..
How we can solve this problem?
The error is because you haven't applied the [Table] attribute (normally it'd go on a class type, in your case the interface type), but I don't see it working even if you did. That's how the mapping is done- when you call GetTable, it looks for the Table attribute to know where to insert/query the data from.
That said, I'm pretty sure you can't do this with an interface. The type on GetTable has to be concrete, because it uses the generic arg passed (or inferred) on GetTable to know what object to create for a query. While it might technically be able to work for inserts, the same GetTable is used for both inserts and queries- which it most certainly won't work for. Same reason XmlSerializer and DataContractSerializer don't work with interfaces.
You'll always need a concrete type, but your entity types can still implement interfaces. I'm guessing you're trying to shuttle these around somewhere (service layer, perhaps), and you'll probably need to rethink that a bit.

Resources