C# WCF - ADO.NET Entity model - DbSet empty? - c#

I created a new WCF project in visual studio based on a existing database.
I made two operations. One operation writes a record (createProfile) to the database and one retrieve data (GetProfiles). My project exists of 3 files: web.config, a edmx file and my svc class.
CreateProfile works fine, I checked in SQL and the record is created.
GetProfiles never gives a response. When I debug the context.UserProfileSet always counts 0 values.
Any suggestions on what is going wrong?
[DataContract]
public partial class UserProfile
{
public int Id { get; set; }
[DataMember]
public string UserName { get; set; }
}
public class MusicOwnerService : IMusicOwnerService
{
IEnumerable<UserProfile> GetProfiles()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
return context.UserProfileSet.AsEnumerable();
}
}
public void CreateProfile()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
context.UserProfileSet.Add(new UserProfile { UserName = "John" });
context.SaveChanges();
}
}
}

As far as I know, you cant pass an IEnumerable object over the wire with WCF (unless youve a duplex binding of some sort??).. so you would be best to convert to a list and return that list like below:
List<UserProfile> GetProfiles()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
return context.UserProfileSet.ToList();
}
}

Related

How to define use the same model within the model

Within my SessionView model I'm trying to assign data from the database into a local variable and then assign this data to the relevant public properties (rather than doing it in the controller).
I'm trying to achieve this by using the following code, but it crashes out when the data is interrogated, presumably because I'm defining the same model within it...
public class SessionView : BaseViewModel
{
public int SessionId { get; set; }
private SessionView data
{
get
{
return (from s in db.Sessions
where s.SessionId == SessionId
select new SessionView
{
CourseId = s.CourseId
// ... lots of other properties
}).FirstOrDefault();
}
set { }
}
public int CourseId { get { return data.CourseId; } set { } }
// ... lots of other properties
}
Is there some clever way I can achieve this without erroring?
Thank you.
I think the best way is to put the data retrieval in the constructor:
In this way, everytime someone reference in this class you only retrieve data once which lessen the retrieval overhead and optimized your code.
In simpler terms, everytime I use the variable data i will query it always from the database.
public class SessionView : BaseViewModel
{
private SessionView _sessionView;
public int SessionId { get; set; }
public SessionView()
{
_sessionView = new SessionView();
_sessionView.data = from s in db.Sessions
where s.SessionId == SessionId
select new SessionView
{
CourseId = s.CourseId
// ... lots of other properties
}).FirstOrDefault();
}
private SessionView data
{
get
{
return _sessionView.data
}
set { }
}
public int CourseId { get { return data.CourseId; } set { } }
// ... lots of other properties
}
Where did you read that Controllers should be thin versus fat Models? Business logic isn't great in the controllers because it would be harder to reuse than if in a business logic tier, but don't confuse that with just database access; that definitely should stay away from the models if you can help it.
This kind of work, assigning a database value to your model - that is exactly what the controller in MVC is meant for. I would opt for something like this.
Model
public class SessionView : BaseViewModel
{
public int SessionId { get; set; }
public int CourseId { get; set; }
// ... lots of other properties
}
Controller
public class HomeController : Controller
{
public ActionResult Index(){
var context = new MyContext();
var firstSession = context.Sessions.First();
var viewModel = new SessionView
{
SessionId = firstSession.SessionId,
CourseId = firstSession.CourseId,
//keep populating here if you need
};
return View(viewModel);
}
}
I think your issue is that the data-loading on your model is actually happening in the view, which is a bad practice in MVC, instead you should do it on the controller, by using a service, something like:
public class SessionController : Controller
{
private readonly ISessionsService sessionService;
public SessionController(ISessionsService sessionsService)
{
this.sessionService = sessionService;
}
public ActionResult SessionData(int sessionId)
{
var sessionData = sessionService.GetById(sessionId);
/// do whatever validation you might require here
var model = new SessionView(sessionData); // you could even pass the sessionId if required here
return View(model);
}
}
you can get your service Dependency-Injected into your controller. I think this is the preferred way to do this on MVC

Adding a new record by using EntityFramework

I am creating a test project in order to learn using asp.net 5 and the mvc 6 framework.
I have decided to create a simple webpage that each menu item comes from the database. To do so I have created a model like such
namespace TestTemplate.Models
{
public class SideMenuItem
{
public int Id { get; set; }
public string Level { get; set; }
public string Label { get; set; }
public string Link { get; set; }
}
}
Inside my Models folder I also have a file named `TestContext.cs'
namespace TestTemplate.Models
{
public class TestContext : DbContext
{
public DbSet<SideMenuItem> SideMenuItems { get; set; }
}
}
That is my EntityFramework DbContext class.
When trying to create a new SideMenu item by using a simple view with a form to adding all the needed data, then using my angular factory that looks like this
return $resource('/api/sidemenu/:id');
I get the error:
An exception of type 'Microsoft.Data.Entity.DbUpdateException' occurred in EntityFramework.Core.dll but was not handled in user code
Additional information: An error occurred while updating the entries. See the inner exception for details.
-->System.Data.SqlClient.SqlException: Invalid object name 'SideMenuItem'.
This error occurs on SideMenuController.cs where I define my API at the part where I am trying to Post the new item:
[HttpPost]
public IActionResult Post([FromBody]SideMenuItem sideMenuItem)
{
if (sideMenuItem.Id == 0)
{
_dbContext.SideMenuItems.Add(sideMenuItem);
_dbContext.SaveChanges(); // ERROR HERE.
return new ObjectResult(sideMenuItem);
}
else
{
var original = _dbContext.SideMenuItems.FirstOrDefault(m => m.Id == sideMenuItem.Id);
original.Level = sideMenuItem.Level;
original.Label = sideMenuItem.Label;
original.Link = sideMenuItem.Link;
_dbContext.SaveChanges();
return new ObjectResult(original);
}
}
I also should mention that before running the app i used
>dnx ef migration add initial
>dnx ef database update
I believe it has to do with me not creating my database correctly. Since I am not seeing any folder on my project that had anything to do with databases or migrations.
Why is it complaining that SideMenuItem is invalid, and how can I fix the issue?
After trying to create my database again, I noticed that I had a typo on my migration command, hence the database was not created.
The command should have been dnx ef migrations ... with an s.
A good starting point with all the commands can be found here.

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

Saving an Item in EF with existing childrens

Im having some problems saving an object (FeatureType) that have a 1-M relationship with Section.
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("SectionId")]
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
If The ItemTypes are new i have no problem and the insert is done correctly.
But if i want to add some existing ItemTypes im getting this Error:
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker.
I have been reading about this problem but i havent found a way to solve it, and it might be because of how its designed my application.
Whem im mappinig from my viewModel to my Model, im getting the section ID and getting the section Object from my SectionRepository as this:
private Section GetSection()
{
var section = _sectionRepository.GetSection(SectionId);
return section;
}
And this is what is giving me the problem, as the section is now been tracked by the SectionRepository that have its own context.
How can i solve this? I have tried just creating a new section with the existing ID but it just create me an empty object.
private Section GetSection()
{
var section = new Section{Id=SectionId};
return section;
}
UPDATE
To save my entity i just use :
_repository.Create(featureType.ToModel());
public FeatureType ToModel()
{
var ft = new FeatureType
{
Name = Name,
ControlType = (ControlType)ControlType,
Order = Order,
Required = Required,
RequiredText = RequiredText,
ItemTypes = GetItemTypes().ToList(),
Section = GetSection(),
};
return ft;
}
UPDATE 2: This is how i have my repositories, i wouldn't like to manage any EF in my controller but with some kind of repository or service.
public class EFBaseRepository
{
protected MyContext Db = new MyContext();
public void Dispose(bool disposing)
{
Db.Dispose();
}
}
public class EFFeatureTypeRepository : EFBaseRepository, IFeatureTypeRepository
{
public IQueryable<FeatureType> GetFeatureTypes
{
get { return Db.FeatureTypes.Include("Section").Include("ItemTypes"); }
}
public Message Create(FeatureType feature)
{
try
{
Db.FeatureTypes.Add(feature);
Db.SaveChanges();
return new Message();
}
catch (Exception e)
{
throw;
// return new Message(e, string.Format("Error Creating {0}", feature.GetType()));
}
}
//..Other Methods
}
You say that the SectionRepository has its own context. That is going to cause you problems. The repositories should share a context. The context is a combination of the unit of work and repository patterns. You need to separate the two patterns:
How to migrate towards unit-of-work and repository pattern
EDIT
You can avoid having the DbContext in the Controller by implementing your own Unit Of Work pattern.
public interface IUnitOfWork : IDisposable
{
ISectionRepository SectionRepository {get;}
//etc
int Save();
}
then in your controller:
public ActionResult Create(FeatureTypeCreate featureType)
{
_Uow.SectionRepository.Create(featureType.ToModel());
_Uow.Save(); //Saving is the responsibility of the Unit Of Work
//not the Repository
}
More references:
Implementing the Repository and Unit of Work
Repository and Unit of Work in Entity Framework
John Papa's original source code
Simply, the error you're getting means that the entities were returned from a different instance of your DbContext than from which they are now trying to be saved. Make sure that you're not doing something like using two different usings around your repository and that your repository always makes use of the same DbContext per instantiation.

MVC 4.0 Controller cannot find seeded data

I am attempting to seed data for an MVC 4 project using SQL server 4.0 as the database engine, using the Microsoft MVC music store tutorial as an example. I have set up a seed and DB context models, but the controller is not able to find the data. I have verified that the the database file is created in App_Data and verified that SetIntitializer is correctly set up in Application_Start. Here is what I have for code:
Seed data:
namespace RationalMethodApp.Models
{
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
{
protected override void Seed(RationalMethodEntities context)
{
new List<Basin>
{
new Basin {
basinId = 1, // attempting to force a key value, will remove
Name = "Replace me with a real basin",
Location = "In a real location",
drainageArea = 0.0M
}
}.ForEach(b => context.Basins.Add(b));
Controller:
public ActionResult Index(int? bsnId)
{
if (bsnId == null) // here to force a key value, will change
bsnId = 1;
var basin = rmDb.Basins.Find(bsnId);
return View(basin);
}
The context class is:
namespace RationalMethodApp.Models
{
public class RationalMethodEntities : DbContext
{
public DbSet<Basin> Basins { get; set; }
public DbSet<SubArea> SubAreas { get; set; }
public DbSet<IdfCurve> IdfCurves { get; set; }
public DbSet<Analysis> Analyses { get; set; }
public DbSet<FlowSegment> FlowSegments { get; set; }
public DbSet<SheetFlowN> SheetFlowNs { get; set; }
public DbSet<RunoffCoefficient> RunoffCoefficients { get; set; }
public DbSet<StormFrequency> stormFrequencies { get; set; }
}
}
The debugger tells me that the "basin" object is still null in the controller after the .Find. This must be a simple, basic thing that I have overlooked, but all of the help I can find on-line assumes that the askers know what they are doing - not true in my case! I have also checked the discussion at Entity Framework database seed doesn't seed
but this does not seem to be the answer. Please bear with a total noob question.
You don't show the full code of you seed, so i can't really be sure, but you might be missing the Context.Changes().
As well you wrote
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
If you don't delete your database before the application start, it won't do anything as the db already exists.
You could use :
public class StartData : DropCreateDatabaseAlways <RationalMethodEntities>
to drop it every time you start or
public class StartData : DropCreateDatabaseAlways <DropCreateDatabaseIfModelChanges >
to drop db when Model changes (which is great for start of dev)
To debug: Drop your database, kill your application server (so it goes back to application start), breakpoint in your seed. Start Debug, if it goes in seed, check that data is in it after SaveChange().

Categories