I am creating a Ntier solution which includes Domain Objects, DataAccess Layer,Service layer and the web API layer . I am using AutoMapper to map Dtos and domain objects in the service layer. I would like to know how to write the logic for performing CRUD operations in the service layer. I have written some mapping. Is this the right way of mapping or is there a better way to do it and also please do correct me where I have written the get, save, update, delete operation. I basically need help in implementing my Service layer.
I am getting the following error when I debug the code:
Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
I get the error at the following line of code in the GetPatient method:
yield return Mapper.Map<PatientDto>(patient);
Domain layer
public class Patient : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public char Gender { get; set; }
public string Phone { get; set; }
}
DataAccess Layer
public class GenericRepository<TEntity> where TEntity : class
{
#region Private member variables...
internal AppointmentBookingContext Context;
internal DbSet<TEntity> DbSet;
#endregion
#region Public Constructor...
/// <summary>
/// Public Constructor,initializes privately declared local variables.
/// </summary>
/// <param name="context"></param>
public GenericRepository(AppointmentBookingContext context)
{
this.Context = context;
this.DbSet = context.Set<TEntity>();
}
#endregion
#region Public member methods...
/// <summary>
/// generic Get method for Entities
/// </summary>
/// <returns></returns>
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = DbSet;
return query.ToList();
}
/// <summary>
/// Generic get method on the basis of id for Entities.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public virtual TEntity GetByID(object id)
{
return DbSet.Find(id);
}
/// <summary>
/// generic Insert method for the entities
/// </summary>
/// <param name="entity"></param>
public virtual void Insert(TEntity entity)
{
DbSet.Add(entity);
}
/// <summary>
/// Generic Delete method for the entities
/// </summary>
/// <param name="id"></param>
public virtual void Delete(object id)
{
TEntity entityToDelete = DbSet.Find(id);
Delete(entityToDelete);
}
/// <summary>
/// Generic Delete method for the entities
/// </summary>
/// <param name="entityToDelete"></param>
public virtual void Delete(TEntity entityToDelete)
{
if (Context.Entry(entityToDelete).State == EntityState.Detached)
{
DbSet.Attach(entityToDelete);
}
DbSet.Remove(entityToDelete);
}
/// <summary>
/// Generic update method for the entities
/// </summary>
/// <param name="entityToUpdate"></param>
public virtual void Update(TEntity entityToUpdate)
{
DbSet.Attach(entityToUpdate);
Context.Entry(entityToUpdate).State = EntityState.Modified;
}
/// <summary>
/// generic method to get many record on the basis of a condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public virtual IEnumerable<TEntity> GetMany(Func<TEntity, bool> where)
{
return DbSet.Where(where).ToList();
}
/// <summary>
/// generic method to get many record on the basis of a condition but query able.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public virtual IQueryable<TEntity> GetManyQueryable(Func<TEntity, bool> where)
{
return DbSet.Where(where).AsQueryable();
}
/// <summary>
/// generic get method , fetches data for the entities on the basis of condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public TEntity Get(Func<TEntity, Boolean> where)
{
return DbSet.Where(where).FirstOrDefault<TEntity>();
}
/// <summary>
/// generic delete method , deletes data for the entities on the basis of condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public void Delete(Func<TEntity, Boolean> where)
{
IQueryable<TEntity> objects = DbSet.Where<TEntity>(where).AsQueryable();
foreach (TEntity obj in objects)
DbSet.Remove(obj);
}
/// <summary>
/// generic method to fetch all the records from db
/// </summary>
/// <returns></returns>
public virtual IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
/// <summary>
/// Inclue multiple
/// </summary>
/// <param name="predicate"></param>
/// <param name="include"></param>
/// <returns></returns>
public IQueryable<TEntity> GetWithInclude(
System.Linq.Expressions.Expression<Func<TEntity,
bool>> predicate, params string[] include)
{
IQueryable<TEntity> query = this.DbSet;
query = include.Aggregate(query, (current, inc) => current.Include(inc));
return query.Where(predicate);
}
/// <summary>
/// Generic method to check if entity exists
/// </summary>
/// <param name="primaryKey"></param>
/// <returns></returns>
public bool Exists(object primaryKey)
{
return DbSet.Find(primaryKey) != null;
}
/// <summary>
/// Gets a single record by the specified criteria (usually the unique identifier)
/// </summary>
/// <param name="predicate">Criteria to match on</param>
/// <returns>A single record that matches the specified criteria</returns>
public TEntity GetSingle(Func<TEntity, bool> predicate)
{
return DbSet.Single<TEntity>(predicate);
}
/// <summary>
/// The first record matching the specified criteria
/// </summary>
/// <param name="predicate">Criteria to match on</param>
/// <returns>A single record containing the first record matching the specified criteria</returns>
public TEntity GetFirst(Func<TEntity, bool> predicate)
{
return DbSet.First<TEntity>(predicate);
}
#endregion
}
Service layer
PatientDto.cs
public class PatientDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public char Gender { get; set; }
public string Phone { get; set; }
}
AutoMapperConfiguration.cs
public class AutoMapperConfiguration
{
public static void Configure()
{
Assembly[] assemblies = BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray();
Mapper.Initialize(cfg =>
cfg.AddProfiles(AllClasses.FromAssemblies(assemblies)
.Where(
a =>
a.FullName.EndsWith("Mapping")))); }
}
DomainToDtoMapping.cs
public class DomainToDtoMapping : Profile
{
public DomainToDtoMapping()
{
CreateMap<BaseEntity, BaseDto>().ReverseMap();
CreateMap<Patient, PatientDto>().ReverseMap();
}
}
IPatientService
public interface IPatientService
{
IEnumerable<PatientDto> GetPatient();
PatientDto GetPatientById(int id);
int CreatePatient(PatientDto customer);
bool UpdatePatient(PatientDto patient);
bool DeletePatient(int patient);
}
PatientService
public class PatientService : IPatientService
{
private readonly IUnitOfWork _unitOfWork;
public int CreatePatient(PatientDto patientDto)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(patientDto.Id);
_unitOfWork.PatientRepository.Insert(patient);
_unitOfWork.Save();
scope.Complete();
return patient.Id;
}
}
public bool DeletePatient(int id)
{
var success = false;
if (id > 0)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(id);
if (patient != null)
{
_unitOfWork.PatientRepository.Delete(patient);
_unitOfWork.Save();
scope.Complete();
success = true;
}
}
}
return success;
}
public IEnumerable<PatientDto> GetPatient()
{
var patient = _unitOfWork.PatientRepository.GetAll();
if (patient != null)
{
yield return Mapper.Map<PatientDto>(patient);
}
yield return null;
}
public PatientDto GetPatientById(int id)
{
var patient = _unitOfWork.PatientRepository.GetByID(id);
if (patient != null)
{
return Mapper.Map<PatientDto>(patient);
}
return null;
}
public bool UpdatePatient(PatientDto patientDto)
{
var success = false;
if (patientDto != null)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(patientDto.Id);
if (patient != null)
{
_unitOfWork.PatientRepository.Update(patient);
_unitOfWork.Save();
scope.Complete();
success = true;
}
}
}
return success;
}
Related
I am trying to create a new ASP.NET application that uses ASP.NET Identity for authentication combined with autofac and Dapper. I know that I have to combine these 2 projects https://github.com/whisperdancer/AspNet.Identity.Dapper and https://developingsoftware.com/configuring-autofac-to-work-with-the-aspnet-identity-framework-in-mvc-5/
but I don't know how to do it.
Update 1:
I am not going to copy all of the code as it exists on the previous links.
I am using the Repository Pattern like this
public class Repository : DataConnection, IRepository
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public Repository(IDbConnection connection)
: base(connection)
{
}
public IDbConnection GetConnection()
{
return Connection;
}
public IEnumerable<T> Select<T>(Expression<Func<T, bool>> objFunc) where T : new()
{
// Orm Lite Version
return Connection.Select<T>(objFunc);
}
public Dictionary<int, string> Dictionary<K, V>(string cacheKey, string Sql)
{
Dictionary<int, string> items = MemoryCache.Default.Get(cacheKey) as Dictionary<int, string>;
if (items == null || !items.Any())
{
items = Connection.Dictionary<int, string>(Sql);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
public Dictionary<int, string> Dictionary<K, V>(string Sql)
{
Dictionary<int, string> items;
items = Connection.Dictionary<int, string>(Sql);
return items;
}
public Dictionary<string, string> DictionaryString<K, V>(string Sql)
{
Dictionary<string, string> items;
items = Connection.Dictionary<string, string>(Sql);
return items;
}
public Dictionary<string, string> DictionaryString<K, V>(string cacheKey, string Sql)
{
Dictionary<string, string> items = MemoryCache.Default.Get(cacheKey) as Dictionary<string, string>;
if (items == null || !items.Any())
{
items = Connection.Dictionary<string, string>(Sql);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
public IList<T> Select<T>(string cacheKey, string Sql, object filter) where T : new()
{
IList<T> items = MemoryCache.Default.Get(cacheKey) as IList<T>;
if (items == null || !items.Any())
{
items = Connection.Select<T>(Sql, filter);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
//where T : new(); has been omitted here as this function returns int, string etc
public T ExecuteScalar<T>(string Sql, object filter)
{
return Connection.ScalarFmt<T>(Sql, filter);
}
public IList<T> Select<T>(string Sql, object filter)
{
IList<T> items;
items = Connection.Select<T>(Sql, filter);
return items;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IEnumerable<T> GetAll<T>() where T : new()
{
// Orm Lite Version
return Connection.LoadSelect<T>();
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="filters"></param>
/// <returns></returns>
public T GetFirst<T>(string cacheKey, object filters) where T : new()
{
T item = (T)MemoryCache.Default.Get(cacheKey);
if (item == null)
{
item = Connection.SingleById<T>(filters);
MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(120));
}
// OrmLite Version
return item;
}
public T GetFirst<T>(object filters) where T : new()
{
T item = Connection.SingleById<T>(filters);
return item;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
public long Add<T>(T instance) where T : new()
{
//Ormlite Version
//Connection.Save(instance);
var Id = Connection.Insert(instance, selectIdentity: true);
return Id;
}
public void Update<T>(T instance) where T : new()
{
//OrmLite version
Connection.Update(instance);
}
public void Delete<T>(object filters) where T : new()
{
Connection.DeleteById<T>(filters);
}
}
where DataConnection Class is like this
public class DataConnection : IDisposable
{
#region Properties
/// <summary>
///
/// </summary>
private IDbConnection _connection;
/// <summary>
///
/// </summary>
protected IDbConnection Connection
{
get
{
if (_connection.State != ConnectionState.Open && _connection.State != ConnectionState.Connecting)
_connection.Open();
return _connection;
}
}
#endregion
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public DataConnection(IDbConnection connection)
{
_connection = connection;
}
public DataConnection(string connString)
{
if (connString == "")
connString = ConfigurationManager.ConnectionStrings[0].Name;
_connection = new SqlConnection(connString);
}
/// <summary>
/// Close the connection if this is open
/// </summary>
public void Dispose()
{
if (_connection != null && _connection.State != ConnectionState.Closed)
{
_connection.Close();
//not sure if this line is needed
_connection.Dispose();
}
//the same for the following line
_connection = null;
}
}
The initial configuration of Autofac is being done in 2 places. In a class named IoC like this
public class IoC : ContainerBuilder
{
/// <summary>
///
/// </summary>
private readonly static IoC _instance = new IoC();
/// <summary>
///
/// </summary>
private static object _lock;
/// <summary>
///
/// </summary>
private IContainer _componentsContainer;
/// <summary>
///
/// </summary>
public static IoC Instance
{
get
{
return _instance;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IContainer GetComponentsContainer()
{
if (_componentsContainer == null)
{
lock (_lock)
{
if (_componentsContainer == null)
_componentsContainer = this.Build();
}
}
return _componentsContainer;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Resolve<T>() where T : class
{
return GetComponentsContainer().Resolve<T>();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ILifetimeScope BeginLifetimeScope()
{
return GetComponentsContainer().BeginLifetimeScope();
}
/// <summary>
///
/// </summary>
private IoC()
{
_lock = new object();
ConfigureDependencies();
}
/// <summary>
///
/// </summary>
private void ConfigureDependencies()
{
//Configure all your depedendencies here!!
//Database connection
var connectionString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerLifetimeScope();
//Database Connection OrmLite
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
//Repository
this.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
this.RegisterType<ApplicationUserStore>().As<IUserStore<AppMember,int>>().InstancePerRequest();
this.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
this.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
this.Register<IAuthenticationManager>(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
}
}
and in ConfigureAuth method of StartUp Class like this
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
//IDataProtectionProvider has to be resolved here as it's the only place where IAppBuilder is available
IoC.Instance.Register<IDataProtectionProvider>(c => app.GetDataProtectionProvider()).InstancePerRequest();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login")
});
}
}
My ApplicationUserStore Class derives from a custom UserSrore Class like this
public class ApplicationUserStore : UserStore<AppMember>
{
public ApplicationUserStore()
: base()
{
}
}
where UserStore is like this
public class UserStore<TUser> : IUserLoginStore<TUser, int>,
IUserClaimStore<TUser, int>,
IUserRoleStore<TUser, int>,
IUserPasswordStore<TUser, int>,
IUserSecurityStampStore<TUser, int>,
IQueryableUserStore<TUser, int>,
IUserEmailStore<TUser, int>,
IUserPhoneNumberStore<TUser, int>,
IUserTwoFactorStore<TUser, int>,
IUserLockoutStore<TUser, int>,
IUserStore<TUser, int>
where TUser : IdentityMember
{
private UserTable<TUser> userTable;
private RoleTable roleTable;
private UserRolesTable userRolesTable;
// This ASP.NET Identity implemantaion won't use claims
private UserClaimsTable userClaimsTable;
private UserLoginsTable userLoginsTable;
private IRepository Repository;
public IQueryable<TUser> Users
{
get
{
throw new NotImplementedException();
}
}
public UserStore()
{
IRepository repository = IoC.Instance.Resolve<IRepository>();
new UserStore<TUser>(repository);
}
/// <summary>
/// Constructor that takes a dbmanager as argument
/// </summary>
/// <param name="database"></param>
public UserStore(IRepository repository)
{
this.Repository = repository;
userTable = new UserTable<TUser>(repository);
roleTable = new RoleTable(repository);
userRolesTable = new UserRolesTable(repository);
//Claims are not implemented
userClaimsTable = new UserClaimsTable(repository);
userLoginsTable = new UserLoginsTable(repository);
}
There is no reason to write all the methods that the UserStore class has, but it is sure that I make a configuration error in Autofac cause this function
public Task<TUser> FindByNameAsync(string userName)
{
if (string.IsNullOrEmpty(userName))
{
throw new ArgumentException("Null or empty argument: userName");
}
List<TUser> result = userTable.GetUserByName(userName) as List<TUser>;
// Should I throw if > 1 user?
if (result != null && result.Count == 1)
{
return Task.FromResult<TUser>(result[0]);
}
return Task.FromResult<TUser>(null);
}
fails with a null reference error. UserTable is not initialised.
Update 2:
UserTable Class
public class UserTable<TUser>
where TUser : IdentityMember
{
private IRepository Repository;
public UserTable(IRepository repository)
{
this.Repository = repository;
}
And IdentityMember Class is custom as well, as follows
public class IdentityMember : IUser<int>
{
/// <summary>
/// Default constructor
/// </summary>
public IdentityMember()
{
}
/// <summary>
/// Constructor that takes user name as argument
/// </summary>
/// <param name="userName"></param>
public IdentityMember(string userName)
: this()
{
UserName = userName;
}
/// <summary>
/// User ID
/// </summary>
[Alias("id")]
public int Id { get; set; }
/// <summary>
/// User's name
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Email
/// </summary>
public virtual string Email { get; set; }
/// <summary>
/// True if the email is confirmed, default is false
/// </summary>
public virtual bool EmailConfirmed { get; set; }
/// <summary>
/// The salted/hashed form of the user password
/// </summary>
public virtual string PasswordHash { get; set; }
/// <summary>
/// A random value that should change whenever a users credentials have changed (password changed, login removed)
/// </summary>
public virtual string SecurityStamp { get; set; }
/// <summary>
/// PhoneNumber for the user
/// </summary>
public virtual string PhoneNumber { get; set; }
/// <summary>
/// True if the phone number is confirmed, default is false
/// </summary>
public virtual bool PhoneNumberConfirmed { get; set; }
/// <summary>
/// Is two factor enabled for the user
/// </summary>
public virtual bool TwoFactorEnabled { get; set; }
/// <summary>
/// DateTime in UTC when lockout ends, any time in the past is considered not locked out.
/// </summary>
public virtual DateTime? LockoutEndDateUtc { get; set; }
/// <summary>
/// Is lockout enabled for this user
/// </summary>
public virtual bool LockoutEnabled { get; set; }
/// <summary>
/// Used to record failures for the purposes of lockout
/// </summary>
public virtual int AccessFailedCount { get; set; }
}
Any Suggestions?
I am using autofac with ASP.NET MVC, using the Repository Pattern.
I have a class like this
public class IoC : ContainerBuilder
{
/// <summary>
///
/// </summary>
private readonly static IoC _instance = new IoC();
/// <summary>
///
/// </summary>
private static object _lock;
/// <summary>
///
/// </summary>
private IContainer _componentsContainer;
/// <summary>
///
/// </summary>
public static IoC Instance
{
get
{
return _instance;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IContainer GetComponentsContainer()
{
if (_componentsContainer == null)
{
lock (_lock)
{
if (_componentsContainer == null)
_componentsContainer = this.Build();
}
}
return _componentsContainer;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Resolve<T>() where T : class
{
return GetComponentsContainer().Resolve<T>();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ILifetimeScope BeginLifetimeScope()
{
return GetComponentsContainer().BeginLifetimeScope();
}
/// <summary>
///
/// </summary>
private IoC()
{
_lock = new object();
ConfigureDependencies();
}
/// <summary>
///
/// </summary>
private void ConfigureDependencies()
{
//Configure all your depedendencies here!!
//Database connection
var connectionString = ConfigurationManager.ConnectionStrings["Pixie"].ConnectionString;
this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerLifetimeScope();
//Database Connection OrmLite
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
//Repository
this.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
}
}
And in my Application_Start method in Global.asax I have the following
protected void Application_Start()
{
//var builder = new ContainerBuilder();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Register your MVC controllers.
IoC.Instance.RegisterControllers(typeof(MvcApplication).Assembly);
IoC.Instance.RegisterModelBinders(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterModelBinderProvider();
IoC.Instance.RegisterModule<AutofacWebTypesModule>();
IoC.Instance.RegisterModule<AutofacWebTypesModule>();
IoC.Instance.RegisterSource(new ViewRegistrationSource());
var MVCControllersResolver = new AutofacDependencyResolver(IoC.Instance.GetComponentsContainer());
}
My Repository is as follows
public class Repository : DataConnection, IRepository
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public Repository(IDbConnection connection)
: base(connection)
{
}
public IDbConnection GetConnection()
{
return Connection;
}
public IEnumerable<T> Select<T>(Expression<Func<T, bool>> objFunc) where T : new()
{
// Orm Lite Version
return Connection.Select<T>(objFunc);
}
}
where DataConnection is a class like this
public class DataConnection : IDisposable
{
#region Properties
/// <summary>
///
/// </summary>
private IDbConnection _connection;
/// <summary>
///
/// </summary>
protected IDbConnection Connection
{
get
{
if (_connection.State != ConnectionState.Open && _connection.State != ConnectionState.Connecting)
_connection.Open();
return _connection;
}
}
#endregion
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public DataConnection(IDbConnection connection)
{
_connection = connection;
}
/// <summary>
/// Close the connection if this is open
/// </summary>
public void Dispose()
{
if (_connection != null && _connection.State != ConnectionState.Closed)
_connection.Close();
}
}
And my controllers are initialized like this
public class QueryController : Controller
{
private IRepository Repository;
public QueryController(IRepository repository)
{
this.Repository = repository;
}
public ActionResult Index()
{
IEnumerable<Product> products = Repository.Select<Product>(q=>q.Id == 1);
return View(products);
}
}
That way I initialize my Repository and my controllers. Now I have the following problem.
I have a class (model) like this
public class OSADCOL
{
public int id { get; set; }
public Nullable<int> TBLid { get; set; }
public Nullable<int> LOVid { get; set; }
public Nullable<int> COLGRPid { get; set; }
public Nullable<int> TabCOLGRPid { get; set; }
}
This class get's its data from the database via requests like this in the controller
IEnumerable<OSQDCOL> osqdcols = Connection.Select<OSQDCOL>("TBLid = #id", new {id = Id });
or
IEnumerable<OSQDCOL> osqdcols = Repository.Select<OSQDCOL>("TBLid = #id", new {id = Id });
Data like this is being used throughout my app in many controllers and is just readonly. Instead of making a new request on the database for every HTTPrequest that needs this data, is there a way to initialise these objects once on Application start? May the singleton pattern is required but I don't know how to implement it using autofac.
Any Ideas?
Register a delegate and resolve the connection inside. This will delay the query until the first resolve. In your controllers you just add List. If this needs to be done once per request and you don't want it to live the entire time change .SingleInstance() to .InstancePerHttpRequest()
IoC.Instance.Register(c =>
{
var conn = c.Resolve<Connection>();
return conn.Select<OSQDCOL>("TBLid = #id", new {id = Id }).ToList();
}).As<List<OSQDCOL>>().SingleInstance();
public QueryController(IRepository repository, List<OSQDCOL> myCachedData)
{
}
You might also look at setting up a CacheService like so:
builder.Register<CacheService>()
.SingleInstance()
.OnActivated(x => x.Instance.InitCache())
.AutoActivate()
.As<ICacheService>()
If your "Connection" is usable during the application startup and the "Id" parameter is always fixed, you can use the following line:
Declare a interface like :
public interface IOsqlcols : IEnumerable<OSQDCOL>
{}
In the registration process, you have to register your interface like this:
var rows = Connection.Select<OSQDCOL>("TBLid = #id", new {id = Id });
IoC.Instance.RegisterInstance(rows).As<IOsqlcols>();
And then, you can resolve your interface in the parameter of your controller
public MyController(IOsqlcols osqlcols)
{
this.osqlcols = osqlcols;
}
By the way, from my point of view, I won't try to override the ContainerBuilder with my own class. Use it as it is.
I am using Glass Mapper for Umbraco. While trying to model something I have a class like:
[UmbracoType(AutoMap = true)]
public class ImageWithLink : BaseUmbracoItem
{
public virtual Image Image { get; set; }
public virtual ?? Link { get; set; }
public virtual string Copy { get; set; }
}
There does not seem to be a 'Link' data type like there is in the Sitecore implementation. I saw This post ( http://bluetubeinc.com/blog/2014/6/glass-mapper-and-umbraco-7) and they use the 'RelatedLink' data type, but that does not exsist ( i checked in the glass repository).
Do I have to model it my self?
Edit: This is the Related Links property type.
Assuming that Umbraco hasn't changed in a while and that you mean a link as in a html anchor...
I may be wrong on this one, but from memory, Umbraco has / had no concept of a link when it comes to the return from the api. It is returned as a node id (or list of) and you must use an extension method to return the url from.
Like you, as far as I can see in the Glass code base, it doesn't have an explicit implementation for a 'link' type like we have in Sitecore.
My guess is that you would have to either roll your own using a custom class and the Delegate feature OR use an integer mapping and call the umbraco api method.
I would also guess is that RelatedLink in that example is mapping to another class which would use the UmbracoPropertyTypeMapper in a similar way to what we do in Sitecore between types, not a 'Link' as in anchor.
We are due to look at umbraco again during the V4 process I believe so talk to Mike about adding it as a feature.
I Found a (rather horrible) solution. Umbraco returns Json, so i had to de-serialize it. You could turn this into a mapper.
[UmbracoType(AutoMap = true)]
public class BaseUmbracoItem : IUmbracoItem
{
public virtual string Links { get; set; }
public List<UmbracoLink> TypedLink
{
get
{
return JsonConvert.DeserializeObject<List<UmbracoLink>>(Links);
}
}
}
public class UmbracoLink
{
public string link { get; set; }
public string type { get; set; }
public string title { get; set; }
public bool newWindow { get; set; }
public bool isInternal { get; set; }
}
Here is a mapper version:
public class UmbracoLinkMapper : AbstractDataMapper
{
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoLinkMapper"/> class.
/// </summary>
public UmbracoLinkMapper()
{
ReadOnly = true;
}
/// <summary>
/// Maps data from the .Net property value to the CMS value
/// </summary>
/// <param name="mappingContext">The mapping context.</param>
/// <returns>The value to write</returns>
/// <exception cref="System.NotSupportedException"></exception>
public override void MapToCms(AbstractDataMappingContext mappingContext)
{
throw new NotSupportedException();
}
/// <summary>
/// Maps data from the CMS value to the .Net property value
/// </summary>
/// <param name="mappingContext">The mapping context.</param>
/// <returns>System.Object.</returns>
public override object MapToProperty(AbstractDataMappingContext mappingContext)
{
var scContext = mappingContext as UmbracoDataMappingContext;
var scConfig = Configuration as UmbracoLinkConfiguration;
var properties = scContext.Content.Properties.Where(x => x.Alias == Configuration.PropertyInfo.Name.ToLower()).ToList();
if (properties.Any())
{
var property = properties.First().Value as string;
return JsonConvert.DeserializeObject<List<UmbracoLink>>(property).First();
}
return null;
}
/// <summary>
/// Indicates that the data mapper will mapper to and from the property
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="context">The context.</param>
/// <returns><c>true</c> if this instance can handle the specified configuration; otherwise, <c>false</c>.</returns>
public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
{
return configuration is UmbracoLinkConfiguration;
}
}
public class UmbracoLinkConfiguration : AbstractPropertyConfiguration
{
public bool IsLazy { get; set; }
public bool InferType { get; set; }
}
public class UmbracoLinkAttribute : AbstractPropertyAttribute
{
public bool IsLazy { get; set; }
public bool InferType { get; set; }
public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
{
var config = new UmbracoLinkConfiguration { IsLazy = IsLazy, InferType = InferType };
Configure(propertyInfo, config);
return config;
}
}
I have problem with this Conference table. The error is :
Invalid column name 'Conference_ConferenceID'
namespace MeetingBoard.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Script.Serialization;
using MeetingBoard.Model.Helpers;
using System.ComponentModel.DataAnnotations.Schema;
/// <summary>
/// A model of the Conference entity. Contains functionality to serialize the entity to JSON as well.
/// </summary>
public class Conference
{
[Key]
public int ConferenceID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int CreatorID { get; set; }
public string Location { get; set; }
public DateTime SubmissionDate { get; set; }
[ForeignKey("CreatorID")]
public virtual User Creator { get; set; }
public int[] RelatedProjectsIDs { get; set; }
public virtual ICollection<ProjectTag> RelatedProjectTags { get; set; }
public DateTime CreatedOn
{
get { return (this.dateCreated == default(DateTime)) ? DateTime.UtcNow : this.dateCreated; }
set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);
public virtual ICollection<Group> RelatedGroups { get; set; }
public Conference()
{
RelatedGroups = new List<Group>();
}
/// <summary>
/// Generates an object that can be serialized by the JSON serializer of MVC
/// </summary>
/// <param name="happening">An Conference.</param>
/// <returns></returns>
public static Object ToJsonObject(Conference conference)
{
int[] project_ids = conference.RelatedProjectTags.Select<ProjectTag, int>(pt => pt.ProjectID).ToArray();
return new Conference_JSON
{
id = conference.ConferenceID,
title = conference.Title,
Content = conference.Content,
created_timestamp_UTC = Util.DateTimeToMilliTimeStamp(conference.CreatedOn),
SubmissionDate = conference.SubmissionDate,
Location = conference.Location,
creator_avatar = conference.Creator.Avatar,
creator_fullname = conference.Creator.Name,
creator_id = conference.Creator.UserID,
project_ids = project_ids,
};
}
/// <summary>
/// Instantiates a new Conference object based on the json data.
/// </summary>
/// <param name="json_data">The json data needs to have the structure as specified in the private Conference_JSON object.</param>
/// <returns>A new Conference object. The related projects are referenced using an integer array containing project ids.</returns>
public static Conference FromJson(String json_data)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Conference_JSON conference_object = serializer.Deserialize<Conference_JSON>(json_data);
return FromJsonObject(conference_object);
}
/// <summary>
/// Instantiates a new Conference object based on the private Conference_JSON object.
/// </summary>
/// <param name="json_data">The object needs to be an instance of the private Conference_JSON object.</param>
/// <returns>A new Conference object. The related projects are referenced using an integer array containing project ids.</returns>
public static Conference FromJsonObject(Object conference_object)
{
Conference_JSON conference_json = (Conference_JSON)conference_object;
Conference conference = new Conference
{
ConferenceID = conference_json.id,
Title = conference_json.title,
Content = conference_json.Content,
RelatedProjectsIDs = conference_json.project_ids,
Location = conference_json.Location,
SubmissionDate = conference_json.SubmissionDate,
};
return conference;
}
/// <summary>
/// Defines the structure of the json objects that ar communicated to and from the Frontend.
/// </summary>
private class Conference_JSON
{
/// <summary>
/// The Conference identifier.
/// </summary>
public int id;
public string title;
public string Content;
/// <summary>
/// An numeric representation of the time, in milliseconds from Unix Epoch, UTC timezone.
/// </summary>
public double created_timestamp_UTC;
public string creator_fullname;
public int creator_id;
public string creator_avatar;
/// <summary>
/// Related projects.
/// </summary>
public int[] project_ids;
public string Location;
public DateTime SubmissionDate;
}
}
}
I get this error when there is a mismatch between the code and the DB, in the sense that the code expects to find columns in the DB but they don't exist there. This happens when the DB isn't updated to match the changes in the code. I'd suggest looking at the database that is being hit when you get that error, maybe it's not looking where you expect.
I am working on a similar project like NerdDinner (www.nerddinner.com).
I have similar tables, but I have used a generic repository (copied from here
http://www.codeproject.com/KB/architecture/linqrepository.aspx).
It seems working without any problem.
Here are the codes.
IRepository.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq;
using System.Linq;
namespace Listing.Repository
{
public interface IRepository<T> where T : class
{
/// <summary>
/// Return all instances of type T.
/// </summary>
/// <returns></returns>
IEnumerable<T> GetAllRows();
/// <summary>
/// Return all instances of type T that match the expression exp.
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
IEnumerable<T> GetAllRowsWhere(Func<T, bool> exp);
/// <summary>Returns the single entity matching the expression. Throws an exception if there is not exactly one such entity.</summary>
/// <param name="exp"></param><returns></returns>
T Single(Func<T, bool> exp);
/// <summary>Returns the first element satisfying the condition.</summary>
/// <param name="exp"></param><returns></returns>
T First(Func<T, bool> exp);
/// <summary>
/// Mark an entity to be deleted when the context is saved.
/// </summary>
/// <param name="entity"></param>
void Delete(T entity);
/// <summary>
/// Adds new entity..
/// </summary>
/// <param name="entity"></param>
void Insert(T entity);
void Update(T entity);
/// <summary>
/// Create a new instance of type T.
/// </summary>
/// <returns></returns>
T New();
/// <summary>Persist the data context.</summary>
void SaveAll();
}
}
Repository.cs
using System;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
namespace Listing.Repository
{
public class Repository<T> : IRepository<T>
where T : class
{
protected Listing.Data.IDataContextFactory _dataContextFactory;
/// <summary>
/// Return all instances of type T.
/// </summary>
/// <returns></returns>
public IEnumerable<T> GetAllRows()
{
return GetTable;
}
/// <summary>
/// Return all instances of type T that match the expression exp.
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
public IEnumerable<T> GetAllRowsWhere(Func<T, bool> exp)
{
return GetTable.Where<T>(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="exp"></param><returns></returns>
public T Single(Func<T, bool> exp)
{
return GetTable.SingleOrDefault(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="exp"></param><returns></returns>
public T First(Func<T, bool> exp)
{
return GetTable.First(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="entity"></param>
public virtual void Delete(T entity)
{
_dataContextFactory.Context.GetTable<T>().DeleteOnSubmit(entity);
}
/// <summary>
/// Create a new instance of type T.
/// </summary>
/// <returns></returns>
public virtual T New()
{
T entity = Activator.CreateInstance<T>();
GetTable.InsertOnSubmit(entity);
return entity;
}
/// <summary>
/// Adds an insance T.
/// </summary>
/// <returns></returns>
public virtual void Insert(T entity)
{
GetTable.InsertOnSubmit(entity);
}
/// <summary>
/// Update entity.
/// </summary>
/// <returns></returns>
public virtual void Update(T entity)
{
_dataContextFactory.Context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, entity);
}
/// <summary>See _vertexRepository.</summary>
public void SaveAll()
{
_dataContextFactory.SaveAll();
}
public Repository(Listing.Data.IDataContextFactory dataContextFactory)
{
_dataContextFactory = dataContextFactory;
}
#region Properties
private string PrimaryKeyName
{
get { return TableMetadata.RowType.IdentityMembers[0].Name; }
}
private System.Data.Linq.Table<T> GetTable
{
get { return _dataContextFactory.Context.GetTable<T>(); }
}
private System.Data.Linq.Mapping.MetaTable TableMetadata
{
get { return _dataContextFactory.Context.Mapping.GetTable(typeof(T)); }
}
private System.Data.Linq.Mapping.MetaType ClassMetadata
{
get { return _dataContextFactory.Context.Mapping.GetMetaType(typeof(T)); }
}
#endregion
}
}
IDataContext.cs
using System;
using System.Linq;
namespace Listing.Data
{
public interface IDataContextFactory
{
System.Data.Linq.DataContext Context { get; }
void SaveAll();
}
public class DataContext : IDataContextFactory
{
#region IDataContextFactory Members
private System.Data.Linq.DataContext dt;
public System.Data.Linq.DataContext Context
{
get
{
if (dt == null)
dt = new Listing.Data.ListingDataContext();
return dt;
}
}
public void SaveAll()
{
dt.SubmitChanges();
}
#endregion
}
}
Now I am in a stage where I have dropped a two functions DistanceBetween and NearestDinners(mine one's name is different), to my dbml file. I want to use these
functions to do some calculation.
Here are the codes used in nerddinner project
public IQueryable<Dinner> FindByLocation(float latitude, float longitude) {
var dinners = from dinner in FindUpcomingDinners()
join i in db.NearestDinners(latitude, longitude)
on dinner.DinnerID equals i.DinnerID
select dinner;
return dinners;
}
How would I achieve similar with my generic Repository.
Help will be appreciated.
Regards
Paraminder
You could use an extension method?
public static IQueryable<Dinner> FindByLocation(this IQueryable<Dinner>, float latitude, float longitude) {
var dinners = from dinner in this
join i in this(latitude, longitude)
on dinner.DinnerID equals i.DinnerID
select dinner;
return dinners;
}