Unable to show the data in databases - asp.net

I am using Entity Framework to access data in databases.
when I debug my code, the List<Book> books contains elements.
However, I can not show it in the HTML page.
If I declare new List<Book>, I can retrieve this
This is not working:
public IEnumerable<Book> GetBooks()
{
List<Book> books = db.Books.ToList();
return books;
}
However, this is working:
public IEnumerable<Book> GetBooks()
{
List<Book> books = new List<Book>
{
new Book {BookId =1, Title="hehe",AuthorId=1,Genre="Trinh Tham" },
new Book {BookId =2, Title="Kaka",AuthorId=2, Genre="Sport"}
};
return books;
}<br />
This is my html page:
<ul id="books"></ul>
<script src="Scripts/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$.getJSON('api/Books/GetBooks').done(function (data) {
$.each(data, function (index, item) {
$("#books").append("<li>" + item.Title + " - " + item.Genre + "</li>");
});
});
});
</script>

Why dont you build the list within the c#/asp.net framework? It wouldn't be too hard ....Please see similar post
Build the ul elements within the html, then add the li from code-behind

I have run into this before. It is most likely a JSON serialization error that won't show up when you are debugging the api controller. To view the actual error message, just copy and paste the url in your browser and it will show the error message. SO if you are debugging in visual studio, just go to http://localhost:[portnumber]/api/Books/GetBooks
If I had to guess, I would say that you have associations (foreign keys) such as Author that are causing the issue. What usually happens is your Entity Framework connection gets disposed before your list can be serialized which throws an error. So you have a few options:
You can create a custom class such as BookJson and just have what you want to be serialized in it so that way your return object has all of the data in it before your api controller goes to serialize it. Plus you can only get the information that you need to serialize instead of the entire object. It would look something like this:
public class BookJson
{
public int BookId {get; set;}
public string Title {get; set;}
public string AuthorName {get; set;}
public string Genre {get; set;}
}
public IEnumerable<BookJson> GetBooks()
{
return db.Books.Select(x => new BookJson { BookId = x.BookId, Title = x.Title, AuthorName = x.Author.Name, Genre = x.Genre}).ToList();
}
Another option is to use the .Include in your db call which will make Entity Framework go ahead and fetch that related data before it gets disposed & serialized. You just need to make sure you include all of your related entities. So something like this:
db.Books.Include("Author").ToList();
The last option is similar to the previous one except you are just disabling lazy loading on the entity framework context so that all related entity data is retrieved. To do this you would just set this option on your data context with:
db.Configuration.LazyLoadingEnabled = false;
db.Books.ToList();

Related

Unwanted unique constraint in many to many relationship

I'm trying to set up a Tagging tool for images. Basically I have two tables, one for pictures, and one for tags. Both are connected with a many to many setup. I can already add a single tag to a picture, and the same tag to different pictures. However, when I try to add a second tag to an image I get an exception complaining about a unique constraint that I simply don't see.
public class MediaEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<TagEntity> Tags { get; set; }
}
public class TagEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<MediaEntity> MediaEntities { get; set; }
}
public void updateMedia(MediaEntity model)
{
using (var db = new MediaContext(_dbLocation))
{
db.Update(model);
db.SaveChanges();
}
}
public class MediaContext : DbContext
{
private const string DB_NAME = "PT.db";
private string _path;
public DbSet<MediaEntity> MediaTable { get; set; }
public DbSet<TagEntity> TagTable { get; set; }
public MediaContext(string path)
{
_path = path;
ChangeTracker.AutoDetectChangesEnabled = false;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite($"Data Source={Path.Combine(_path, DB_NAME )}");
}
As far as I can tell my setup should create a normal many-to-many relationship, and it the database I also see pretty much this. EF automatically creates a TagTable, MediaTable, and MediaEntityTagEntityTable. But when I try to add a second tag I get this:
SqliteException: SQLite Error 19: 'UNIQUE constraint failed:
MediaEntityTagEntity.MediaEntitiesId, MediaEntityTagEntity.TagsId'.
Data from the table showing I can have the same tag on different pictures:
MediaEntitiesId
TagEntitiesId
1B48E85B-F097-4216-9B7A-0BA34E69CBFF
CF581257-F176-4CDF-BF34-09013DCEAA27
CE33F03F-5C80-492B-88C6-3C40B9BADC6C
CF581257-F176-4CDF-BF34-09013DCEAA27
523178A1-C7F8-4A69-9578-6A599C1BEBD5
0C45C9D1-7576-4C62-A495-F5EF268E9DF8
I don't see where this unique constaint comes in. How can I set up a proper many-to-many relationship?
I suspect the issue you may be running into is with the detached Media and associated Tags you are sending in. You are telling EF to apply an 'Update' to the media, but the DbContext will have no idea about the state of the Tags attached. Assuming some tags may have been newly attached, others are existing relationships. If the Context isn't tracking any of these Tags, it would treat them all as inserts, resulting in index violations (many to many) or duplicate data (many to one / one to many)
When dealing with associations like this, it is generally simpler to define more atomic actions like: AddTag(mediaId, tagId) and RemoveTag(mediaId, tagId)
If you are applying tag changes along with potential media field updates in a single operation I would recommend rather than passing entire entity graphs back and forth, to use a viewModel/DTO for the tag containing a collection of TagIds, from that apply your tag changes against the media server side after determining which tags have been added and removed.
I.e.:
public void updateMedia(MediaViewModel model)
{
using (var db = new MediaContext(_dbLocation))
{
var media = db.Medias.Include(x => x.Tags).Single(x => x.MediaId = model.MedialId);
// Ideally have a Timestamp/row version number to check...
if (media.RowVersion != model.RowVersion)
throw new StaleDataException("The media has been modified since the data was retrieved.");
// copy media fields across...
media.Name = model.Name;
// ... etc.
var existingTagIds = media.Tags
.Select(x => x.TagId)
.ToList();
var tagIdsToRemove = existingTagIds
.Except(model.TagIds)
.ToList();
var tagIdsToAdd = model.TagIds
.Except(existingTagIds)
.ToList();
if(tagIdsToRemove.Any())
media.Tags.RemoveRange(media.Tags.Where(x => tagIdsToRemove.Contains(x.TagId));
if(tagIdsToAdd.Any())
{
var tagsToAdd = db.Tags.Where(x => tagIdsToAdd.Contains(x.TagId)).ToList();
media.Tags.AddRange(tagsToAdd);
}
db.SaveChanges();
}
}
Using this approach the DbContext is never left guessing about the state of the media and associated tags. It helps guard against stale data overwrites and unintentional data tampering (if receiving data from web browsers or other unverifiable sources), and by using view models with the minimum required data, you improve performance by minimzing the amount of data sent over the wire and traps like lazy load hits by serializers.
I always explicitly create the join table. The Primary Key is the combination of the two 1:M FK attributes. I know EF is supposed to map automatically, but since it isn't, you can specify the structure you know you need.

Linq to Entities method: Select and ToListAsync

I want to retrieve only a few columns in the query. I want to achieve this query using entity framework:
select FirstName from Employee
However, I am not able to use Select and ToListAsync at the same time. I am getting an error and it looks like I can't use both at the same time.
Is there any other way to do this?
[HttpGet]
public async Task<ActionResult<IEnumerable<Employee>>> GetEmployee()
{
return await _context.Employee.Select(s => s.FirstName).ToListAsync();
}
Gert's comment covered the reason for the error. It will be due to the function expecting a set of Employee entity entities but you are trying to just return a set of employee names by using Select(s => s.FirstName)
If your intention is to return just Employee names, then update the method signature to something like:
public async Task<ActionResult<IEnumerable<string>>> GetEmployeeNames()
Typically situations like this will be when you want to return something like search results or a summary list. You don't necessarily want to return everything about employees (and possibly serializing related data on top of that) just for displaying a list of employee names for users to select from. Still, returning just an employee name isn't much use on its own in case you want to select one of them and request more information or perform an action against them. (Not to mention you could have two "Peter"s as employees...)
In these cases it is helpful to define a simple view model to represent just the data the front end will need. For example the employee name and ID:
[Serializable]
public class EmployeeSummaryViewModel
{
public int EmployeeId { get; set; }
public string Name { get; set; }
}
Then the method to retrieve the employees:
[HttpGet]
public async Task<ActionResult<IEnumerable<EmployeeSummaryViewModels>>> GetEmployeeSummaries()
{
return await _context.Employee
.Select(s => new EmployeeSummaryViewModel
{
EmployeeId = s.EmployeeId,
Name = s.FirstName + " " + s.LastName
}).ToListAsync();
}
The view model is a simple serializable C# class. By leveraging Select to populate it, EF can generate a very efficient query to return just those fields we want. This can include fields from related tables such as a Role or such without needing to worry about eager loading or serializing everything from those related tables.
In the above example the view model contains the ID for each employee returned so we can pass that ID to future calls if needed, such as selecting an employee to load a complete view of, or perform an action against. The server also formats the name. Alternatively you can return the FirstName and LastName and leave the formatting up to the client side.
Based on your code, I think you would need something like this:
[HttpGet]
public async Task<ActionResult> GetEmployee()
{
var employeeNames = await _context.Employee.Select(s => s.FirstName).ToListAsync();
return Ok(employeeNames);
}
Since your return type is ActionResult<IEnumerable<Employee>> .simply use below code to return List of Employee
[HttpGet]
public async Task<ActionResult<IEnumerable<Employee>>> GetEmployee()
{
var result = await _context.Employee
.Select(s => new Employee
{
Name = s.FirstName
}).ToListAsync();
return Ok(result);
}
It's wrong syntax. You just change like this:
[HttpGet]
public async Task<ActionResult<IEnumerable<string>>> GetEmployee()
{
return await _context.Employee.Select(s => s.FirstName).ToListAsync();
}
or
[HttpGet]
public async Task<IActionResult> GetEmployee()
{
return Ok(await _context.Employee.Select(s => s.FirstName).ToListAsync());
}

Xamarin forms - Realm accessed from incorrect thread

Maybe I'm missing something really simple out here but gonna ask anyways.....
I am using Xamarin forms (.NET Standard project), MVVMLight, Realm DB and ZXing Barcode Scanner.
I have a realmobject like so...
public class Participant : RealmObject
{
public string FirstName {get; set;}
public string LastName {get; set;}
public string Email {get; set;}
public string RegistrationCode {get; set;}
//More properties skipped out for brevity
}
I have the corresponding viewmodel as follows:
public class ParticipantViewModel
{
Realm RealmInstance
public ParticipantViewModel()
{
RealmInstance = Realms.Realm.GetInstance();
RefreshParticipants();
}
private async Task RefreshParticipants()
{
//I have code here that GETS the list of Participants from an API and saves to the device.
//I am using the above-defined RealmInstance to save to IQueryable<Participant> Participants
}
}
All the above works fine and I have no issues with this. In the same viewmodel, I am also able to fire up the ZXing Scanner and scan a bar code representing a RegistrationCode.
This, in turn, populates the below property (also in the viewmodel) once scanned...
private ZXing.Result result;
public ZXing.Result Result
{
get { return result; }
set { Set(() => Result, ref result, value); }
}
and calls the below method (wired up via the ScanResultCommand) to fetch the participant bearing the scanned RegistrationCode.
private async Task ScanResults()
{
if (Result != null && !String.IsNullOrWhiteSpace(Result.Text))
{
string regCode = Result.Text;
await CloseScanner();
SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));
if (SelectedParticipant != null)
{
//Show details for the scanned Participant with regCode
}
else
{
//Display not found message
}
}
}
I keep getting the below error....
System.Exception: Realm accessed from incorrect thread.
generated by the line below....
SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));
I'm not sure how this is an incorrect thread but any ideas on how I can get around to fetching the scanned participant either from the already populated IQueryable or from the Realm representation directly would be greatly appreciated.
Thanks
Yes, you're getting a realm instance in the constructor, and then using it from an async task (or thread). You can only access a realm from the thread in which you obtained the reference. Since you're only using a default instance, you should be able to simply obtain a local reference within the function (or thread) where you use it. Try using
Realm LocalInstance = Realms.Realm.GetInstance();
at the top of the function and use that. You'll need to recreate the Participants query to use the same instance as its source too. This will be the case wherever you use async tasks (threads), so either change all to get hold of the default instance on entry or reduce the number of threads that access the realm.
Incidentally I'm surprised you don't get a similar access error from within
RefreshParticipants() - maybe you're not actually accessing data via RealmInstance from there.

Update database items from the website

My current problem is (probably) not necessarily directly related to MVC 6, but how working with database actually works, and therefore any help/suggestions in this matter would be more than appreciated.
For the sake of this question, let's say that we have a very simple database with the following tables (C# classes) [we are using Entity Framework to work with the database]:
public class ShoppingUser
{
public int Id { get; set; }
public string UserName { get; set; }
public ICollection<ShoppingItem> Items { get; set; }
}
public class ShoppingItem
{
public int Id { get; set; }
public string Quantity { get; set; }
public string Text { get; set; }
public bool ToRemove { get; set; }//if item has been bought, it can be removed from the shopping list
}
This demo will be for a super duper simple shopping list app, where user (ShoppingUser who is registered in the system can have a List of ShoppingItem where user can decide on what is the text of the item (e.g. Bread, Butter, Tomatoes, ...) and also a quantity (3 pieces, 5kg, ... simple string)
Afterwards in my ASP.NET Core app, I have defined a repository which is communicating with the database and has access to the ShoppingItem class (as we are only interested in shopping items of currently logged in user).
Example of some method we could use here:
public IEnumerable<ShoppingItem> ReturnUserItems(string sUsername)
{
if (string.IsNullOrWhiteSpace(sUsername))
return null;
var result = _context.ShoppingUsers.Include(n => n.Items).Where(n => n.UserName == sUsername).FirstOrDefault();
if (result != null)
return result.Items;
else
return null;
}
Finally we have an API controller with JsonResult for either GET, POST, DELETE, ..., which is used for communication between client side AngularJs App and our server side logic.
Example of GET Method:
// GET: /<controller>/
[HttpGet("")]
public JsonResult Get(string sUserName)
{
try
{
var results = _repository.ReturnUserItems(User.Identity.Name);
if (results != null)
{
var result = Mapper.Map<IEnumerable<ShoppingItemViewModel>>(results);
return Json(result);
}
Response.StatusCode = (int)HttpStatusCode.OK;
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = ex.Message });
}
return null;
}
Here comes the tricky part (at least for me). From video tutorials I have learned, that I should never (or almost never) expose my real database model to the website (I guess it's for security reasons). Due to that (as visible from my GET method above) I have declared my ShoppingItemViewModel which contains only properties I want to expose to the user (e.g. meaning that Id of my item is not visible).
This is how it looks like:
public class ShoppingItemViewModel
{
public string Quantity { get; set; }
[Required]
public string Text { get; set; }
[Required]
public bool ToRemove { get; set; }//if item has been bought, it can be removed from the shopping list
}
And for the communication from my AngularJS App I am using simple $http.get and $http.post calls for retrieving / posting updated data.
Finally the question:
My problem is, that if a user decides to either delete an item from his shopping list, or decides to change the content of either text / quantity (meaning that originally in the database it was tomatoes - 5 kg but he manages to buy only 2 kg and therefore changes the quantity to tomatoes - 3kg), how can the app understand which elements have actually been changed and how? The problem I have in this case is, that we are no longer exposing the database Id of the items.
If I was writing a desktop app, where I wouldn't have to create this sub view (ShoppingItemViewModel), my EntityFramework is intelligent enough to check & update all the changes in my database. Unfortunately in this case, I do not understand how this is achievable.
When I was thinking about it I came with the following: Add a new property into the ShoppingItem and ShoppingItemViewModel: public string sCustomKey {get; set; }, which would serve as a unique key for every item. This way, we no longer need to expose our database Id, but we are exposing the 'fake' one.
Second question:
I case my solution would be accurate, what is the best way to update items in the database? The only way I can think of is iterating through all the items in the database and manually check for changes?
Example of what I have in mind:
//IEnumerable<ShoppingItem> would be re-mapped result of ShoppingItemViewModel we have received back from the website
public void UpdateValues(IEnumerable<ShoppingItem> items, string sUserName)
{
//retrieves list of shopping items for specified customer
var allItems = _context.ShoppingUsers
.Include(n => n.Items)
.FirstOrDefault(n => n.UserName == sUserName);
//updates the values
foreach (var sItem in items)
{
var updatedItem = allItems.Items.FirstOrDefault(n => n.Text == sItem.sCustomKey);
if (updatedItem == null)
{
//create new item
var newItem = new ShoppingItem();
newItem.Text = sItem.Text;
newItem.ToRemove = sItem.ToRemove;
allItems.Items.Add(newItem);
}
else
updatedItem.ToRemove = sItem.ToRemove;
}
_context.SaveChanges();
}
But this approach does not seem right to me.
Any help regarding these matters would be more than appreciated as I am still learning how to work with ASP.NET Core and web projects.
In your first question, exposing the item ID in the ViewModels is fine. In your domain layer, you can add validation logic that those ID exists/valid item.
Alternatively, you can use a Guid for your item/product because the ID (int) can easily be predicted.
As far as updating the items, you should not use the "username" as Identifier (of the cart) because that can be predicted/altered by the calling client. You can use Guid either persisted(to Db) or
in-memory. You can add validation as well if this Guid belongs to this username/emailAddress. So updating the items in the cart, consider adding/removing one at a time if that is doable
instead of sending list of items.
I think you have misunderstood something.
Here comes the tricky part (at least for me). From video tutorials I have learned, that I should never (or almost never) expose my real database model to the website (I guess it's for security reasons). Due to that (as visible from my GET method above) I have declared my ShoppingItemViewModel which contains only properties I want to expose to the user (e.g. meaning that Id of my item is not visible).
ViewModel <=> Domain Model <=> ReadModel (Database Model)
The point is that you shouldn't use your ReadModel(Database model) as your ViewModel in Presentation Layer (MVC). All three models will have identity.

Error displaying details (ObjectContext instance has been disposed)

I'm building an ASP.NET MVC 3 app and I've got a model that looks something like so:
public partial class Flavor
{
// ...
public string Name { get; set; }
public bool HasNuts {get; set; }
public virtual ICollection<SaleData> Sales {get; set;}
// ...
}
which retrieves some data from a db as such:
public PartialViewResult Details(int id)
{
using (var db = new IceCreamDBFlavors())
{
Flavor someFlavor = db.Flavors.Find(id);
someFlavor.Sales = db.Sales.Where(c => c.FlavorID == id).ToList();
return PartialView("details", someFlavor);
}
}
over on the view I do something like this:
<fieldset>
<legend>Sales Data</legend>
#foreach (var sale in Model.Sales)
{
<div>Weekly</div>
<div>#sale.Weekly</div>
}
</fieldset>
If I don't retrieve the Sales data, my Flavor data displays fine with no errors, but adding the call to retrieve the list of sales data causes an error "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." to occur.
I've read a few other posts about this and guess I'm missing something here. I believe this error happens due to lazy loading, at least based on what I've read here and elsewhere. Setting a breakpoint in the Controller before returning the PartialView and checking the object, I believe, causes the evaluation to take place, so everything displays as I would want.
I was under the impression that the ToList() call would force the Sales collection to be filled in. Since I don't have the issue when that line's commented out, I assume the problem is still related to that and when the View is attempting to iterate the Sales, it can't. Am I correct here? I guess I thought I was forcing the evaluation. How do I resolve this?
My suspicion is that Flavor has other collections (and not just Sales) and it is in fact at the time of accessing those that it breaks.
Here you are replacing only Sales while other collections or complex properties would still need the object context.
Don't dispose the IceCreamDBFlavors class that inherits from ObjectContext, it needs to have a lifetime greater than is currently allowed.
Change
using (var db = new IceCreamDBFlavors())
{
Flavor someFlavor = db.Flavors.Find(id);
someFlavor.Sales = db.Sales.Where(c => c.FlavorID == id).ToList();
return PartialView("details", someFlavor);
}
To
try
{
var db = new IceCreamDBFlavors();
Flavor someFlavor = db.Flavors.Find(id);
someFlavor.Sales = db.Sales.Where(c => c.FlavorID == id).ToList();
return PartialView("details", someFlavor);
}
catch(Exception ex)
{
// log exeption
}

Resources