I've successfully completed a few examples used to create Web API Odata services. Such as:
Create model class "Employee"
Create controller "EmployeesController"
Use GET /Employees to get list of records
These examples would create a SQL table called "Employees". How would I map this model\controller to an existing SQL table called "corpemployee"?
Thanks
You need to execute the sql statement first and map the result to the Employee object, for example:
public class EmployeesController:ODataController
{
public IHttpActionResult Get()
{
string sql="select * from corpemployee";
// Create a database connection
// Execute the sql statement
IList<Employee> employees=new List<Employee>();
Employee employee=new Employee();
foreach(var result in resultset)
{
Employee employee=new Employee();
emmployee.ID=result["ID"];
// Other properties go here
employees.Add(employee);
}
return Ok(employees);
}
}
Definitely there are other options, such as using O/R mapping framework:
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/NHibernateQueryableSample/.
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataDollarFormatSample/, which uses Entity Framework.
Related
I created a generic user repository base class that provides reusable user management functionality.
public class UserRepository<TUser> where TUser : new, IUser
{
}
I have a concrete implementation of IUser called UserImpl, and corresponding mapping class UserImplMap : ClassMap<UserImpl> (they all are in the same namespace and assembly). I add the mapping using AddFromAssemblyOf . I also use this to create / generate the schema.
So far so good and things work as expected.
Now, in a different project, I needed a few additional properties in my IUser implementation class, so I implemented a new class UserImplEx : UserImpl. This class has the additional properties that I needed. Also, I created a new mapping class UserImplExMap : SubclassMap<UserImplEx>
Now when I create schema using this approach, I get two tables one for UserImpl and one for UserImplEx.
Is is possible to configure / code Fluent mapping in some way so that all the properties (self, plus inherited) of UserImplEx get mapped in a single table UserImplEx instead of getting split into two tables?
Alternatively, if I provide full mapping in UserImplExMap : ClassMap<UserImplEx>, then I do get the schema as desired, but I also get an additional table for UserImpl (because corresponding mapping is present in the UserRepository assembly). If I follow this approach, is there a way to tell AddFromAssemblyOf to exclude specific mapping classes?
Option 1
since you have inhertance here and want the correct type back NH has to store the type somewhere, either through the table the data is in or a discriminator.
If a discriminator column in the table does not matter then add DiscriminatorColumn("userType", "user"); in UserImplMap and DiscriminatorValue("userEx") in UserImplExMap
Option 2
class MyTypeSource : ITypeSource
{
private ITypeSource _inner = new AssemblyTypeSource(typeof(UserImplMap).Assembly);
public IEnumerable<Type> GetTypes()
{
return _inner.Where(t => t != typeof(UserImplMap)).Concat(new [] { typeof(UserImplExMap) });
}
public void LogSource(IDiagnosticLogger logger)
{
_inner.LogSource(logger);
}
public string GetIdentifier()
{
return _inner.GetIdentifier();
}
}
and when configuring
.Mappings(m =>
{
var model = new PersistenceModel();
PersistenceModel.AddMappingsFromSource(new MyTypeSource());
m.UsePersistenceModel(model);
})
I created a database in Azure setting my own custom name. I then created EF 5 code first entities and added migrations. On application startup I called these two lines:
Database.DefaultConnectionFactory = new SqlConnectionFactory(connectionString);
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, MyConfiguration>());
Connection string is taken straight from Azure:
Server=tcp:xxx.database.windows.net,1433;Database=dbName;User ID=yyy;Password=zzz;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;
On fist call I expected database dbName to be filled with tables according to POCO schema.
But instead a NEW database is generated with the complete namespace name of my context:
MyService.Business.Entity.MyContext
Why will the migration not accept the database name specified in the connection string?
You can specify the Database name or connection string name in the constructor of your DbContext:
public class MyDataContext : DbContext
{
public MyDataContext: base("DbNameOrConntectionStringNameHere")
{
}
}
My experience is that, in the case where the connection string is being passed in code, rather than obtained from app.config, EF is quirky about how it obtains the connection string.
I had to add a class that inherited from IDBContectFactory
public class ContextFactory : IDbContextFactory<Context>
{
public Context Create()
{
var s = (string)AppDomain.CurrentDomain.GetData("ConnectionString");
var context = new Context(s);
return context;
}
}
Also, in order to create a migration, I needed the following in my context class
// uncomment when creating migration - comment out after migration is created
public Context() : base("ConnectionStringName"){}
Where the ConnectionStringName is set up in my app.config.
I am still mystified that I had to do this and have asked about it here
I have several stored procedures that don't return the domain objects (i.e; objects which have corresponding sql table mapping in hbm files); but return the custom objects instead.
I want to call these stored procedures using NHibernate and fill my custom objects with the output automatically, instead of filling them mannually as I would do if I use a SqlDataReader.
An example shall be highly appreciated.
BTW: I use nhibernate 3.2 new feature mapping by code.
Maybe you can try the following (taken from https://stackoverflow.com/a/10513319/1236044 )
It uses CreateSQLQuery. You may try replacing the select... with Exec MyStoredProc
The key point is having your select or stored procedure return columns with the same name as the properties of the DTO you are trying to populate.
public class YourDto
{
public int YourDtoId { get; set; }
public string YourDtoTitle { get; set; }
}
then
var result = yourNhSession
.CreateSQLQuery("select yourColumn1 as YourDtoId, yourColumn2 as YourDtoTitle from YOUR_TABLE")
.SetResultTransformer(Transformers.AliasToBean<YourDto>())
.List<YourDto>();
I have a WCF/REST web service that I'm considering using Linq to SQL to return database info from.
It's easy enough to do basic queries against tables and return rows, for example:
[WebGet(UriTemplate = "")]
public List<User> GetUsers()
{
List<User> ret = new List<User>(); ;
using (MyDataContext context = new MyDataContext())
{
var userResults = from u in context.Users select u;
ret = userResults.ToList<User>();
}
return ret;
}
But what if I want to return data from multiple tables or that doesn't exactly match the schema of the table? I can't figure out how to return the results from this query, for example:
var userResults = from u in context.Users
select new { u.userID, u.userName, u.userType,
u.Person.personFirstname, u.Person.personLastname };
Obviously the resulting rowset doesn't adhere to the "User" schema, so I can't just convert to a list of User objects.
I tried making a new entity in my object model that related to the result set, but it doesn't want to do the conversion.
What am I missing?
Edit: related question: what about results returned from stored procedures? Same issue, what's the best way to package them up for returning via the service?
Generally speaking, you shouldn't return domain objects from a service because if you do you'll run into issues like those you're finding. Domain objects are intended to describe a particular entity in the problem domain, and will often not fit nicely with providing a particular set of data to return from a service call.
You're best off decoupling your domain entities from the service by creating data transfer objects to represent them which contain only the information you need to transfer. The DTOs would have constructors which take domain object(s) and copy whatever property values are needed (you'll also need a parameterless constructor so they can be serialized), or you can use an object-object mapper like AutoMapper. They'll also have service-specific features like IExtensibleDataObject and DataMemberAttributes which aren't appropriate for domain objects. This frees your domain objects to vary independently of objects you send from the service.
You can create a Complex Type and instead of returning Anonymous object you return the Complex Type. When you map stored procedures using function import, you have a option to automatically create a complex type.
Create a custom class with the properties that you need:
public class MyTimesheet
{
public int Id { get; set; }
public string Data { get; set; }
}
Then create it from your Linq query:
using (linkDataContext link = new linkDataContext())
{
var data = (from t in link.TimesheetDetails
select new MyTimesheet
{
Id = t.Id,
Data = t.EmployeeId.ToString()
}).ToList();
}
Not sure if I have the correct terminology, but I am a little confused on how to set up my 3-tier system.
Lets say I have a table of Users in my DB.
In my DAL, I have a UserDB class that calls stored procs into he DB to insert, update, delete.
I also have a UserDetails class that is used in UserDB to return and pass in objects.
So now I am not sure how to use this in my Business Logic Layer. Do I need another BLL object class for users? If so, would this not be redundant?
Or do I just use the UserDetails class throughout my BLL?
Look up a concept called 'Domain Driven Design' - the biggest thing there is using what's called a repository pattern (such as your UserDB class) as an adapter to the database, as well as a factory. Your business objects, or domain objects, then incorporate business logic into themselves and can handle interactions with other business objects.
What technology are you using? Something like ActiveRecord can probably help you a lot.
You typically would enforce Business Rules in your BLL. For example, you might allow regular call center employees to offer a 10% discount on new service but allow a manager to offer a 20% discount. You would have a business rule in your BLL that goes something like:
// Pseodocode
double Discount
{
set
{
if (value > 10% AND Employee Is Not Manager) then throw Exception
if (value > 20%) then throw Exception
discount = value;
}
}
You can use following design:
DAL:
namespace DAL.Repository
{
public class UsersRepository
{
public static IList GetUser(string UserId)
{
using(MyDBEntities context=new MyDBEntities())
{
// it calls SP in DB thru EF to fetch data
//here you can also context.user to fetch data instead of SP
return context.GetUser(UserId).ToList();
}
}
}
}
BLL
namespace BLL
{
public class User
{
public static IList GetUser(string UserId)
{
return DAL.Repository.UserRepository.GetUser(UserId);
}
}
}
PL
ddlUser.DataTextField = "UserName";
ddlUser.DataValueField = "UserId";
ddlUser.DataSource= BLL.User.GetUser(string.Empty);
ddlUser.DataBind()
Note: while sending data from BL to PL converting DB Entity to Business entity is required if you want to loop thu data in PL.