Using a Database Context in multiple projects within the same solution - c#

I'm currently working on a program that is being used to generate PDF's and documents. There are two different use cases, one being an automated process and the second being a manual process where data can be edited via a front-end app.
The solution has 2 Projects in it, the first for the automated part, and the second for the manual part.
However, since the two processes make use of the same data and templates, I've split the solution into two parts, this will allow me to set it up in a way in which I only need to maintain models/templates once.
My database context looks like this:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RefundTracker.Models
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
:base("Prod")
{
}
public DbSet<Referral> Referrals { set; get; }
public DbSet<ReferralAppointment> ReferralAppointments { set; get; }
public DbSet<ReferralPayment> ReferralPayments { set; get; }
public DbSet<BankDetails> BankDetails { set; get; }
public DbSet<ReferralAppointment_History> ReferralAppointment_History { set; get; }
public DbSet<ReferralPayment_History> ReferralPayment_History { set ; get; }
public DbSet<IsInUse> IsInUse { set; get; }
}
}
In terms of projects, I have a project called "RefundTracker" and another called "MailMergeTPA".
The context provided above, together with all of the models, are located in the "RefundTracker" project.
I would like to make use of these models and context in the "MailMargeTPA" project as well.
I referenced the "RefundTracker" in "MailMergeTPA" project, however, no results when using the context here. (When I access a function that get a list of names for instance, I get the full list in "RefundTracker", however, I get no results when I use the same function in "MailMergeTPA".
Code Example:
public BankDetails GetBankDetails(Referral record)
{
string bName = record.bankName.Trim();
try
{
BankDetails bankDetails= new BankDetails();
List<BankDetails> bankDetails = new List<BankDetails>();
using (DatabaseContext db = new DatabaseContext())
{
bankDetails = db.BankDetails.SingleOrDefault(a => a.BankName == bName);
}
return bankDetails;
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
return null;
}
I would like to make use of this exact function in both projects.
Could you kindly help me with some advice? (Please go easy on me in the comments, I'm still fairly new to EF)
I've tried referencing the project, no result.
I've read up on interfaces, however, I'm unsure as to how I would incorporate this.

Related

How do I implement a simple "complex type" in Entity Framework Core 2/C#?

I'm using Entity Framework and .Net Core 2.0 for the first time (I'm also pretty new to C#, but I've been using the traditional .Net Framework & VB since version 1... so I'm no newbie to .Net development), and I've already run into a problem creating my database.
Take this simple scenario: I want to store some information about some electric pumps. Two of the properties are a min/max type range, so I've implemented these as a simple class, thus:
public class Pump
{
[Key]
public int pumpId { get; set; }
public string pumpName { get; set; }
public int pumpControlChannel { get; set; }
public MinMax normalCurrent { get; set; }
public MinMax normalFlowRate { get; set; }
}
[ComplexType]
public class MinMax
{
public int min { get; set; }
public int max { get; set; }
}
As you can see, I've tried the [ComplexType] decorator, to no avail.
Anyway, now create a dead simple DBContext class to manage my Pumps class. I'm using Sqlite:
public class EFDB : DbContext
{
public DbSet<Pump> pumps { get; private set; }
private static DbContextOptions GetOptions(string connectionString)
{
var modelBuilder = new DbContextOptionsBuilder();
return modelBuilder.UseSqlite(connectionString).Options;
}
public EFDB(string connectionString) : base(GetOptions(connectionString)) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
try
{
// modelBuilder.ComplexType<MinMax>(); // ComplexType not recognised
base.OnModelCreating(modelBuilder);
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break();
}
}
}
and lastly a simple static class to call it (I embeded it in a bigger program... to duplicate this problem you could just stick the code lines into program.cs):
public static class TryMe
{
public static void MakeMeFail()
{
using (var db = new EFDB("FileName=C:\\temp\\test_effail.db"))
{
try
{
db.Database.EnsureCreated();
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break(); // If we hit this line, it fell over
}
}
System.Diagnostics.Debugger.Break(); // If we hit this line, it worked.
}
}
Just call TryMe.MakeMeFail(), the code fails at db.Database.EnsureCreated().
From everything I've read, [ComplexType] should do what I want... but it Just Doesn't. Nor can I find modelBuilder.ComplexType<T> anywhere.
It may just be a library reference I'm missing...? The above code uses the following:
using System;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
However, NONE of the documentation/examples I can find anywhere show which libraries need referencing!
Thanks in advance.
[PS: Apologies to those who already saw this question, I'm using EF Core 2.0, NOT EF6]
Typical... it's always the way, isn't it? 5 minutes after posting, you discover the answer to your own question....
The answer, in this case, can be found here:
https://learn.microsoft.com/en-us/ef/core/modeling/owned-entities
EF Core calls this sort of entity an "owned" entity, rather than a "complex type".
Simply adding these lines to `OnModelCreating' fixed the issue:
modelBuilder.Entity<Pump>().OwnsOne(p => p.normalCurrent);
modelBuilder.Entity<Pump>().OwnsOne(p => p.normalFlowRate);
The database now creates (correctly, I think, I haven't verified that yet).

DynamoDB C# expression to query/scan

I have a generic repository structure in place using interfaces and I am trying to develop a DynamoDB implementation for this. This is my first experience with DynamoDB and NoSQL (previously all T-SQL).
The problem I am having is that I am unable to find any way of converting a lambda expression in C# to a format that I can use to query/scan DynamoDB.
My Get method looks like this:
public Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> where)
{
return await this.DataContext.ScanAsync(...);
}
Is there an existing way to do this? There doesn't seem to be anything in the documentation that addresses this and I am struggling to find an example of where someone else has had a similar problem.
Maybe my lack of experience with NoSQL and/or DynamoDB is just the problem here. If so, please do point out a better approach if necessary though I will note that as previously mentioned, I am implementing an interface which is already defined and changing this isn't really an option.
As far as I know, you can use the ServiceStack.Aws, which is similar to LINQ.
For example:
using System;
using Amazon;
using Amazon.DynamoDBv2;
using ServiceStack;
using ServiceStack.Text;
using ServiceStack.Aws.DynamoDb;
using ServiceStack.DataAnnotations;
var awsDb = new AmazonDynamoDBClient("keyId","key",
new AmazonDynamoDBConfig { ServiceURL="http://localhost:8000"});
var db = new PocoDynamo(awsDb);
public class Todo
{
[AutoIncrement]
public long Id { get; set; }
public string Content { get; set; }
public int Order { get; set; }
public bool Done { get; set; }
}
db.RegisterTable<Todo>();
db.DeleteTable<Todo>(); // Delete existing Todo Table (if any)
db.InitSchema(); // Creates Todo DynamoDB Table
var newTodo = new Todo {
Content = "Learn PocoDynamo",
Order = 1
};
db.PutItem(newTodo);
var savedTodo = db.GetItem<Todo>(newTodo.Id);
"Saved Todo: {0}".Print(savedTodo.Dump());
savedTodo.Done = true;
db.PutItem(savedTodo);
var updatedTodo = db.GetItem<Todo>(newTodo.Id);
"Updated Todo: {0}".Print(updatedTodo.Dump());
db.DeleteItem<Todo>(newTodo.Id);
var remainingTodos = db.GetAll<Todo>();
"No more Todos: {0}".Print(remainingTodos.Dump());

Retrieving records from another SQL Server database - Umbraco

I'm working on a website, where I need to retrieve pricelists, from another database on the same SQL Server as my Umbraco database.
It's a requirement that it has to be in a separate database.
I have made a new connection string Pricelist and used EF database-first.
PriceList repository:
namespace UmbracoCMS.Repository{
using System;
using System.Collections.Generic;
public partial class Prisliste
{
public string Kode { get; set; }
public string Speciale { get; set; }
public string Ydelsesgruppe { get; set; }
public string Gruppe { get; set; }
public string Ydelse { get; set; }
public string Ydelsestekst { get; set; }
public string Anaestesi { get; set; }
public string Indlæggelse { get; set; }
public Nullable<double> Listepris { get; set; }
public Nullable<int> WebSort { get; set; }
public string YdelsesTekstDK { get; set; }
public string Frapris { get; set; }
public Nullable<int> Sortering { get; set; }
}
}
PriceListController class:
using System;
using System.Linq;
using System.Web.Mvc;
using UmbracoCMS.Repository;
namespace UmbracoCMS.Controllers{
public class PriceListController : Umbraco.Web.Mvc.SurfaceController {
[HttpGet]
public PartialViewResult GetPriceList(string contentTitle){
var db = new PricelistContext();
var query = from b in db.Prislistes orderby b.Speciale select b;
Console.WriteLine("records in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Speciale);
}
return PartialView("~/views/partials/PriceList.cshtml");
}
}
}
What I want is to load the prices for a treatment, based on a property on the document type. I'm just not sure how do this in umbraco since I'm fairly new a umbraco.
So when a treatment page is requested, I need to take the property ContentTitle value. Use it to retrieve all records with the same Speciale and display them in a list/table.
With a query
.where(b.Speciale = contentTitle)
It would be great if someone could help a little, or lead me in the right direction.
Also is it possible to do it in the same http request? Or should I use partial view or macros to both get the properties of the document type, from the umbraco database, and the records from the pricelist database at the same time when a user go to the treatment page?
Or is there a better way to do this?
Update:
Thanks a lot, for the great answer Ryios.
I got a question more.
using System;
using System.Linq;
using System.Web.Mvc;
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult GetPriceList(string contentTitle)
{
PricelistContext.RunInContext(db =>
{
var result = db.Prislistes.OrderBy(p => p.Speciale);
});
return View(result);
}
}
}
I got it working, so it call the method and the data from the Pricelist Database is shown in:
var result = db.Prislistes.OrderBy(p => p.Speciale);
Now I just need to get the list of prices out to the view again, so I can show a list or table of the prices.
Do you have a suggestion on how I can this in Umbraco. Normally I would return a ViewModel in MVC like:
return View(new ListViewModel(result));
and use it in the view like:
#model Project.ViewModels.ListViewModel
So I can loop through it.
But I want to still have the properties from the the "Home"/"TreatmentPage" Document type.
Should I do it with a partialView or is there a better way?
Solved
I thought I wanted to share it, if anyone else is in a similar situaction.
Controller:
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public PartialViewResult PriceList(string contentTitle)
{
List<Prisliste> result = null;
PricelistContext.RunInContext(db =>
{
result = db.Prislistes.Where(p => p.Speciale == contentTitle)
.OrderBy(p => p.Speciale).ToList();
});
var model = result.Select( pl => new PrislistVm()
{
Speciale = pl.Speciale,
Listepris= pl.Listepris
});
return PartialView(model);
}
}
}
ViewModel:
namespace UmbracoCMS.ViewModels
{
public class PrislistVm
{
public PrislistVm()
{
Results = new List<Prisliste>();
}
public List<Prisliste> Results { get; set; }
public string Speciale { get; set; }
public double listepris { get; set; }
}
}
View/PriceListSurface:
#model IEnumerable<UmbracoCMS.ViewModels.PrislistVm>
#{
ViewBag.Title = "PriceList";
}
<h2>PriceList</h2>
#foreach (var item in Model)
{
#item.Speciale
#item.Listepris
}
Your going to have a memory leak if you load your EF context like that. I recommend creating a method to wrap it for you with a llambda callback. Put it in your context class.
public static void RunInContext(Action<PricelistContext> contextCallBack)
{
PricelistContext dbContext = null;
try
{
dbContext = new PricelistContext();
contextCallBack(dbContext);
}
finally
{
dbContext.Dispose();
dbContext = null;
}
}
//Example Call
PricelistContext.RunInContext(db => {
var result = db.PrisListes.OrderBy(p => p.Speciale);
//loop through your items
});
To get the Value of the DocumentType, it depends on the calling context. Assuming you are using a Razor Template that is attached to the document type, that is associated with a Content Page.
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "ContentPageLayout.cshtml";
}
#* Call GetPriceList on PriceListController with Parameter contentTitle *#
#Html.Action("GetPriceList", "PriceListSurface", new { contentTitle = Model.Content.GetPropertyValue<string>("ContentTitle") });
In the above example, I have created a document type with a property called ContentTitle that is associated with a view called ContentPage. Then I created content in the backoffice Content section called "Home" that uses the document type. Giving me a url like
http://localhost/home
Also, your SurfaceController will not work. Umbraco's logic for mapping the routes for surface controllers has some requirements for your surface controller's naming conventions. You have to end the name of the class with "SurfaceController" and then it get's called PriceListSurfaceController, then it maps the controller with a name of "PriceListSurface".
Here's the documentation for the SurfaceController features.
http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
Using a surface controller is the right logic. It's not good practice to have your Data Layer code calls in the UmbracoTemplatePage. 1, because RazorTemplates are interpreted/compiled and SurfaceController's are JIT compiled int the dll, so SurfaceController code is WAY faster. 2 Because you can make asynchronous Controller calls in MVC Razor. If it was all in the view it would make it really difficult to convert everything to be asynchronous. It's best to keep server side logic in a controller.
Optionally, you can Hijack an Umbraco route and replace it with a custom controller that doesn't have to inherit from SurfaceController, which makes it possibly to surface content to the browser that is or isn't part of umbraco.
http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers
You can also create a new section in the backoffice to manage your Price List "the ui framework for building one is written against AngularJS"
http://www.enkelmedia.se/blogg/2013/11/22/creating-custom-sections-in-umbraco-7-part-1.aspx

ASP.NET MVC placing userID in hidden field

I am using ASP.NET MVC 5 Razor
I am trying to apply the membership userID to a hidden field so that I can associate table data to a spceific user.
(users completes a form that is stored in a table, userID used to associate to login profile)
I just don't know how to do this and is an important part of my current project and future projects.
Any guidance, advice, links to solutions would be of great help as I am completely at a loss with this.
I tried passing the data from the model class for the view but I get an error saying "The name 'User' does not exist in the current context"
this is an extract of my model class
using System;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Globalization;
using System.Web.Security;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace mySite_Site.Models
{
[Table("accountInfo")] // Table name
public class accountInfo
{
[Key]
public int AccountID { get; set; }
public int UserIdent { get; set; } //this is the field that would store the userID for association
public string LastName { get; set; }
public string FirstName { get; set; }
public string Locality { get; set; }
public string EmailAddress { get; set; }
public bool Active { get; set; }
public DateTime LastLoggedIn { get; set; }
public string UserIdentity = User.Identity.GetUserId();
}
Expanding on Brandon O'Dell's answer, using "Membership" in that block of code didn't work for me (unhandled errors). Nevertheless, I think his approach to this solution is great because it means you can call the current user's Id from practically anywwhere. So, I went on ahead and played a little bit with the code, and voilá!.
In case using "Membership" doesn't work for you as well, try this one:
using <your project's name>.Models
public class GeneralHelpers
{
public static string GetUserId()
{
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.FirstOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
return user.Id;
}
}
This one gets the whole user, so, you can create even more methods inside this "GeneralHelper" class (or whatever name you wish to give it) to get the current user's info and use it in your application.
Thanks, Brandon!
You just need something like this, assuming your ViewModel has the user profile on it.
#Html.HiddenFor(m=>m.UserProfile.UserId)
Since your model is not in the controller, you need to explicitly tell the code Where the user object is, which is contained in the HttpContext. So, update this line here:
public string UserIdentity = User.Identity.GetUserId();
to the following
public string UserIdentity = HttpContext.Current.User.Identity.GetUserId();
The controller and view base classes have a reference to the current HttpContext, which is why you can shortcut in those items and simply use User.Identity. Anywhere else in your project, you will need the fully qualified HttpContext.Current.User.
Edit
In further looking at your code, it looks like you are trying to save the user Id as a column in your database. In that instance, I think (based on your code sample) that you should remove that last part - public string UserIdentity = User.Identity.GetUserId();. When you save a new account info object, that is where you would save the user id.
var info = new accountInfo();
accountInfo.UserIdent = HttpContext.Current.User.Identity.GetUserId();
db.accountInfos.Add(info);
db.SaveChanges();
Why not just create a static helper class?
public static class UserUtils
{
public static object GetUserId()
{
return Membership
.GetUser(HttpContext.Current.User.Identity.Name)
.ProviderUserKey;
}
}

Odata Navigation property causing 404 error

I have been looking around for an answer to this question, but I don't think anyone on SO has faced this exact problem. Really briefly, I am using the reflection provider in C# to create an odata service (like so), and will have two entities: Blocks and Roots.
Blocks are much like files and directories in a filesystem, some can have children blocks and some cannot. Roots are like different user accounts, and a device can only belong to one Root. Here's what I have so far:
Classes.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Data.Services.Common;
using System.Data.Services;
[DataServiceEntity]
public class Block
{
public string Name { set; get; }
public int ID { set; get; }
public int PID { set; get; }
}
public class ParentBlock : Block
{
public List<Block> Children { set; get; }
public int Count { get { return Children.Count(); } }
public ParentBlock()
{
Children = new List<Block>();
}
}
/*other classes that inherit from Block or ParentBlock*/
[DataServiceEntity]
[DataServiceKey("User")]
public class Root
{
public string User { set; get; }
public int ID { set; get; }
public List<Block> Children { set; get; }
public Root()
{
Children = new List<Block>();
}
}
Main.cs
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class RootDataService : DataService<RootService>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.UseVerboseErrors = true;
config.DataServiceBehavior.MaxProtocolVersion = System.Data.Services.Common.DataServiceProtocolVersion.V2;
}
}
public class RootService
{
private List<Root> RootList = new List<Root>();
private List<Block> BlockList = new List<Block>();
public RootService()
{
/*initializes RootList and BlockList with test data*/
}
public IQueryable<Root> Roots
{
get
{
return RootList.AsQueryable<Root>();
}
}
public IQueryable<Block> Blocks
{
get
{
return BlockList.AsQueryable<Block>();
}
}
}
This all works pretty well. I run the program, navigate to my browser and I get two collections, Roots and blocks. I can do odata/Roots to get both test accounts, odata/Roots('account1') to get the first account's User and ID. I can do odata/Roots('account1')/Children(5) and get the Block with ID of 5.
But... when I try to do odata/Roots('account1')/Children(5)/Children or odata/Block(5)/Children, I get a 404. This is frustrating since I added validation code to my RootService constructor and the Count property shows that Block(5) has children (2 of them), but I cannot navigate to them? I'm certain there's something pretty obvious that I'm missing, but I haven't found it. More baffling is that both Root and ParentBlock have identical code in regards to making their Children list available to outside classes, but only one of them is navigable. I am grateful for any help!
In your model, the Block type does not have a property called Children. Did you mean to refer to ParentBlock instead of Block in your Blocks entity set and Root.Children property?
Or, if you know that Block(5) happens to be a ParentBlock, you can cast it before accessing its Children property. For example:
odata/Block(5)/YourNamespace.ParentBlock/Children

Categories