I am new to Entity Framework and having a hard time figuring out what I am doing wrong.
Using ASP.Net MVC, C# and EF6 on a normal SQL database.
Here is my controller code.
using (var context = new MyEntities())
{
var result = context.Streamers.OrderBy(x => x.AddedDate);
foreach (var item in result)
{
var linkResult = context.Links.Where(x => x.StreamerId == item.Id);
item.Links = linkResult.ToList();
}
return View(result.ToList());
}
Here is my View
#{int i = 0;}
#foreach (var streamer in Model)
{
var className = i % 2 == 0 ? "col-lg-6 order-lg-2" : "col-lg-6";
var className2 = i % 2 == 0 ? "col-lg-6 order-lg-1" : "col-lg-6";
i++;
<section>
<div class="container">
<div class="row align-items-center">
<div class="#className">
<div class="p-5">
<a href="#streamer.StreamerUrl" target="_blank">
<img class="img-fluid rounded-circle" src="#streamer.StreamerImage" alt="#streamer.StreamerName">
</a>
</div>
</div>
<div class="#className2">
<div class="p-5">
<a href="#streamer.StreamerUrl" target="_blank">
<h2 class="display-4">#streamer.StreamerName</h2>
</a>
<p>#streamer.StreamerDescription</p>
<ul>
#foreach (var link in streamer.Links)
{
<li>#link.LinkName</li>
}
</ul>
</div>
</div>
</div>
</div>
</section>
}
The code is erroring out on the for each for streamer.Links
System.ObjectDisposedException: 'The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.'
Can anyone help me figure out what I am doing wrong here? Is there a much simpler way to be doing this?
Thanks in advance
Your DbContext is likely disposed. When for loop hits, Link is not attached to the context and cannot load the navigational property with the address. Load your link addresses when querying the links:
context.Links.Include(c => c.LinkAddress).Where(x => x.StreamerId == item.Id);
Try this if you don't want to change Html:
using (var context = new MyEntities())
{
result = context.Streamers.Include(c => c.Links)
.OrderBy(c=> c.AddedDate).ToList();
}
Try to use this code:
List<Streamer> result;
using (var context = new MyEntities())
{
result = context.Streamers.OrderBy(x => x.AddedDate).ToList();
foreach (var item in result)
{
item.Links = = context.Links.Where(x => x.StreamerId == item.Id).ToList();
}
}
return View(result);
but since you are not filtering streamers you can try this:
using (var context = new MyEntities())
{
result = context.Streamers.Include("Links").OrderBy(x => x.AddedDate).ToList();
}
Related
I am unit testing a blazor app. I get a ElementNotFoundException. I think the cause for this is an if statement in the the index.razor page. see code below:
<div class="row">
<div class="col-12">
#if ((challenges != null) && (challenges.Count > 0))
{
<MultiStepComponent Id="MultiStepContainer" Challenges="#challenges">
<div class="row p-3">
<div class="col-6" id="challengeContainer">
#foreach(var c in challenges)
{
<MultiStepNavigation Name="#c.Title">
<h1>#c.Title</h1>
<img class="float-left" src="#c.ImagePath" width="200" />
#foreach(var sentence in c.Description)
{
<p>#sentence</p>
}
</MultiStepNavigation>
}
</div>
<div class="col-6">
<textarea rows="26" cols="120" #bind="input" id="input"></textarea>
<button class="btn" id="runBtn" #onclick="RunAsync">Run</button>
<br />
<textarea rows="10" cols="120" id="output" readonly>#((MarkupString)Output)</textarea>
</div>
</div>
</MultiStepComponent>
}
</div>
</div>
The code behind of this page (index.razor.cs) has the following initialization code:
protected override async Task OnInitializedAsync()
{
jsonRepository = new JSONChallengeRepository();
challenges = await jsonRepository.GetChallengesAsync();
}
The test for this page is here:
[Test]
public async Task Compile_code_Success()
{
_codingChallengeService.Setup(c => c.SendInputToCompilerAsync("50+50")).ReturnsAsync("100");
_testContext.Services.AddScoped(x => _codingChallengeService.Object);
var razorComponent = _testContext.RenderComponent<Index>();
razorComponent.Instance.challenges = GetChallenges();
if ((razorComponent.Instance.challenges != null) && (razorComponent.Instance.challenges.Count > 0))
{
var runBtn = razorComponent.FindAll("button").FirstOrDefault(b => b.OuterHtml.Contains("Run"));
var input = razorComponent.Find("#input");
input.Change("50+50");
runBtn.Click();
var outputArea = razorComponent.Find("#output");
var outputAreaText = outputArea.TextContent;
Assert.AreEqual("100", outputAreaText);
}
Assert.IsNotNull(razorComponent.Instance.challenges);
}
The #input is missing..Why??
Thanks in advance!
I am guessing the problem is that you do not cause the component under test to re-render when you assign razorComponent.Instance.challenges property/field, and if the component does not re-render, then the markup inside #if ((challenges != null) && (challenges.Count > 0)) block in the component is not displayed.
In general, dont mutate properties (parameters) of components through the razorComponent.Instance. If you really have to do so, make sure to trigger a render after.
Instead, pass parameters to the component through the RenderComponent or SetParametersAndRender methods, or through services injected into components. That will cause the component to go through its normal render life-cycle methods.
I am currently trying to add a new row for each 3rd column with razor. However, with the current code, only the first three columns get wrapped in a row, and the rest get skipped. I have been looking around for a fix, but none of it seems to work with my code. Does anyone have a solution for this?
#model IEnumerable<Byporten.createpost>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_LayoutClient.cshtml";
}
<div class="container">
#{
var itemCount = 0;
}
#while (itemCount < 3)
{
foreach (var item in Model.Reverse().Take(9))
{
if(itemCount == 0 )
{
#:<div class="row">
}
<div class="col-lg-4 col-md-6 col-sm-6">
<div class="image-section">
<img src="~/images/uploads/#Html.DisplayFor(modelItem => item.ImageURL)"/>
</div>
<div class="title-section">
<h5><span class="fa fa-pencil"></span> #Html.DisplayFor(modelItem => item.Title)</h5>
#Html.ActionLink("Les mer", "viewArticle", new { id = item.Id })
</div>
</div>
itemCount++;
if ((itemCount % 3) == 0)
{
#:</div>
}
}
}
#{itemCount = 0;}
</div>
None of these worked for me, but the following did:
#foreach (var item in Model.Items)
{
var itemCount = 0;
foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
if (itemCount == 0)
{
#:<div class="row">
}
<div class="col-md-4">
<span class="organogram-outter-ring"></span>#listItem.Fields.Title
<div style="display:none;" class="sf-list-content">
#Html.Raw(listItem.Fields.Content)
</div>
<div class="organogram-outter-ring"></div>
</div>
if (itemCount == 2)
{
itemCount = 0;
#:</div>
}
else
{
itemCount++;
}
}
}
It's going to result in invalid markup because itemCount == 0 will be true only once. Replace if (itemCount == 0) with if (itemCount % 3 == 0 || itemCount % 3 == 3).
I would also get rid of the while loop and the itemCount reset at the bottom.
Use Html.Raw() method to avoid compilation problems with conditional closing tag, and temp variable insertRow to avoid repeating in row condition:
<div class="container">
#{
var itemCount = 0;
}
#{
foreach (var item in Model.Reverse().Take(9))
{
var insertRow = itemCount % 3 == 0;
if(insertRow)
{
#Html.Raw("<div class="row">")
}
<div class="col-lg-4 col-md-6 col-sm-6">
<div class="image-section">
<img src="~/images/uploads/#Html.DisplayFor(modelItem => item.ImageURL)"/>
</div>
<div class="title-section">
<h5><span class="fa fa-pencil"></span> #Html.DisplayFor(modelItem => item.Title)</h5>
#Html.ActionLink("Les mer", "viewArticle", new { id = item.Id })
</div>
</div>
if (insertRow)
{
#Html.Raw("</div>")
}
itemCount++;
}
}
</div>
And also while (itemCount < 3) loop is look strange and unnecessary for your task.
So, I know I am a little late to the game and there is an accepted answer, however, I want to add my rendition because it requires no duplicate if statements and no code compilation squigglies.
My approach uses an inner for loop based on the number of columns you want to have before creating a new row:
<table>
<thead>
<tr>
<td><b>My List Data:</b></td>
</tr>
</thead>
<tbody>
#{
var items = Model.MyList;
const int colCount = 2;
}
#for (var i = 0; i < items.Count(); i += colCount)
{
<tr>
#for (var c = 0; c < colCount && i + c < items.Count(); c++)
{
<td>#(items[i + c].Display):</td>
}
</tr>
}
</tbody>
</table>
The premise is to determine what your column count is, that is show above using const int colCount =2;
Then, loop, using a for loop, on your list but instead of incrementing by 1, as is traditional, increment by your colCount value.
Then, have your row tag. This means a row will be created every n+colCount items.
Within that row tag, have another for loop that increments by 1 until you either reach your colCount OR your parent iterator plus your colCount iterator equals or exceeds the total items in your list.
Within that for loop, simply create a cell that is at the index of i (outer iterator) + c (colCount) iterator.
This gives you a nice left to right, top to bottom table structure from a flat list without extra if statements and compilation warnings.
We're developing news website we're confused with some concept of usage. I'd like to ask and know better if possible. We've a homepage which may contain a lot of models at once so we're separating our homepage to partial views and we're planning to feed them with the appropriate models.
In one partial we're enumerating in categories that are not marked as deleted and we've two types of categories. One of them displays the latest post and the other displays 4 posts at once. We've achieved this actually but as i've mentioned we would like to know if there is a better way or if we're doing anything wrong because right now we're keeping the connection to the context open until the partial is rendered.
Here is the code for views
Partial View Code (CategoryRepeater.cshtml)
#using SosyalGundem.WebUI.DatabaseContext;
#{
var categoryList = new List<PostCategories>();
var db = new SosyalGundemDb();
categoryList = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList();
}
#for (int i = 0; i < categoryList.Count; i++)
{
if (i % 3 == 0 || i == 0)
{
#Html.Raw("<div class=\"row-fluid spacer\">")
}
var category = categoryList[i];
if (category.PostCategoryType == 1)
{
<div class="span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
var article = category.Posts.FirstOrDefault();
if (article != null)
{
<article class="post">
<div class="entry clearfix">
<div class="span6">
<a href="#" title="Permalink to Suspen disse auctor dapibus neque pulvinar urna leo" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/uploadedimages/" + article.Media.ToList()[0].MediaContent )" alt="shutterstock_70184773" />
</a>
</div>
<div class="span6">
<h4 class="smallnewstitle">#article.PostTitle</h4>
<p>#(article.PostSummary.Length > 100 ? article.PostSummary.Substring(0, 100) : article.PostSummary)</p>
<div class="meta">
<span class="date">#article.PostDate.ToString("MMMM dd, yyyy")</span>
</div>
</div>
</div>
</article>
}
}
</div>
}
else
{
<div class="video-box widget span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
int cati = 0;
var firstPost = category.Posts.OrderByDescending(x => x.PostDate).FirstOrDefault();
}
#if (firstPost != null)
{
<h4 class="smallnewstitle">#firstPost.PostTitle</h4>
<p>#(firstPost.PostSummary.Length > 100 ? firstPost.PostSummary.Substring(0, 100) : firstPost.PostSummary) </p>
<ul>
#foreach (var item in category.Posts.OrderByDescending(x => x.PostDate))
{
if (cati <= 3)
{
<li>
<a href="#" title="#item.PostTitle" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/images/dummy/shutterstock_134257640-225x136.jpg")" alt="shutterstock_134257640" />
</a>
</li>
}
else
{
break;
}
cati++;
}
</ul>
}
</div>
}
if (i % 3 == 0 && i != 0)
{
#Html.Raw("</div>")
}
}
#{
db.Dispose();
}
Separate your concerns. You can see this project for start: http://www.codeproject.com/Tips/617361/Partial-View-in-ASP-NET-MVC
Controller
#using SosyalGundem.WebUI.DatabaseContext;
public ActionResult SomeAction()
{
var model = new CategoriesModel
{
NotDeletedCategories = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList(),
DeletedCategories = db.PostCategories.Include("Posts").Where(x => x.IsDeleted).ToList()
};
return View(model);
}
Model
public class CategoriesModel
{
public List<PostCategories> NotDeletedCategories {get;set;}
public List<PostCategories> DeletedCategories {get;set;}
};
View
#model CategoriesModel
#Html.RenderPartial("DeletedCategories", Model.DeletedCategories)
#Html.RenderPartial("NotDeletedCategories", Model.NotDeletedCategories)
Hi Jinava,
I would suggest bind Model to the View,
Like,
public ActionResult CategoryRepeater()
{
var multiViewModel = new MultiViewModelModel
{
ModelForParialView1= new XYZ(),
ModelForParialView2= new PQR()
};
return View(model);
}
For the View
#model MultiViewModelModel
And then PAss the views with the MultiViewModelModel.ModelForParialView1 and MultiViewModelModel.ModelForParialView2
You can perform all the model operations on the view.
And at the controller level perform all the database operations and release the database connection there itself no need to get that on the view.
Hope this explanation helps you.
I am at very basic stage of asp.net MVC development. So sometimes I struggle with simple LINQ queries to work.
scenario-
I have A page that has some Image and comment on that Image by users (Just Like a post on facebook containing comments from users).
So I am saving those comments from the textarea and sending Image ID via Ajax query.
Here Is my controller action method-
Saving comment-
[HttpPost]
public void SaveComment(CardModel card) {
CardCommentTable commenttable = new CardCommentTable();
commenttable.CardComment = card.cardComment;
commenttable.FKcardID = card.cardID;
db.CardCommentTables.InsertOnSubmit(commenttable);
db.SubmitChanges();
}
This Comment is saved in CardCommentTable that has foreign key reference of Table in that Image is saved.
Rendering Image and other fields on view page-
This query renders Image and other fields that make it An Image post. Like title, dateofsubmit, Like etc.
public ActionResult CardDetails(CardModel card) {
var cardDetail = (from u in db.CardTables
where u.CardID == card.cardID
select new CardModel {
cardID = u.CardID,
cardHashCode = u.CardHashCode,
cardDate = u.CardDate,
cardFileName = u.CardFileName,
cardFilePath = u.CardFilePath,
cardTitle = u.CardTitle
}).ToList();
return View(cardDetail);
}
Now In cardTable I have one more column named cardComment in that I want to show all those saved comments from table CardCommentTable.
So I tried-
public ActionResult CardDetails(CardModel card) {
var allsavedcomments= (from u in db.CardCommentTables
where u.FKcardID == card.cardID
select u).ToList();
var cardDetail = (from u in db.CardTables
where u.CardID == card.cardID
select new CardModel {
cardID = u.CardID,
cardHashCode = u.CardHashCode,
cardDate = u.CardDate,
cardFileName = u.CardFileName,
cardFilePath = u.CardFilePath,
cardTitle = u.CardTitle,
cardComment = allsavedcomments // Trying to render all saved coments here.
}).ToList();
return View(cardDetail);
}
View-
#model IEnumerable<FunRanger.Models.CardModel>
#foreach (var item in Model) {
<script type="text/javascript">
$(function () {
$('#save-comment').click(function () {
var textareavalue = $('#textarea-comment').val();
$.ajax({
url: '/Home/SaveComment/',
type: 'post',
data: '&cardComment=' + textareavalue + '&cardID=' + '#item.cardID',
success: function (data) {
$('#all-comments').append(data);
}
});
});
});
</script>
using (Html.BeginForm()) {
#Html.ValidationSummary(true)
#if (Model != null) {
<h2 class="header-wrapmain">
#item.cardTitle
</h2>
#item.cardDate.ToShortDateString()
<img src="#item.cardFilePath" />
<a href="#" class="#item.cardHashCode" rel="tooltip" data-placement="bottom" title="Filter by #item.cardHashCode">
##item.cardHashCode</a>
}
else {
<div class="alert alert-danger">
No More items to preview
</div>
}
}
<textarea class="span12" rows="5" id="textarea-comment" style="resize: none" placeholder="Enter a comment..."></textarea>
Save comment
<ol>
<li>
#item.cardComment
</li>
</ol>
}
How can I insert List result in a column here.
How do I show all saved comments with this above query?
Thanks for any help.
I slightly renovated your code with Foreign key relations ship. This will save your from using two different queries to your database (like what you are doing now).
So if you Database Model looks like this -
Then you should have one viewmodel in your code in this way -
public class ImageViewModel
{
public string ImageId { get; set; }
public string ImageUrl { get; set; }
public List<string> Comments { get; set; }
}
And your controller action which will return all the results should be like this -
public class ListController : Controller
{
public ActionResult Index()
{
ImageViewModel model;
using (SampleEntities entities = new SampleEntities())
{
model = (from p in entities.Images
where p.ImageId == "1"
select new ImageViewModel()
{
ImageId = p.ImageId,
ImageUrl = p.ImageUrl,
Comments = p.ImageComments.Select(pa => pa.Comment).ToList()
}).FirstOrDefault();
}
return View(model);
}
}
Finally the view which will display all the Image results -
#model MVC.Controllers.ImageViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div>
<h4>ImageViewModel</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.ImageId)
</dt>
<dd>
#Html.DisplayFor(model => model.ImageId)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ImageUrl)
</dt>
<dd>
#Html.DisplayFor(model => model.ImageUrl)
</dd>
<br/>
#foreach (var item in Model.Comments)
{
#item <br/>
}
</dl>
</div>
Output would be -
Your cardComment property is a list of strings; it needs to be iterated in order to be displayed. Replace:
<ol>
<li>
#item.cardComment
</li>
</ol>
with:
<ol>
#foreach (var singleComment in Model.cardComment)
{
<li>#singleComment </li>
}
</ol>
I need to change the CSS class of the <div> tag with the 'forumChild' class. It has to change every 3 loops of the foreach loop.
Is there a way to do this from within the control?
<div class="Forum">
<p>The Forum</p>
#foreach (var item in Model)
{
<div class="ForumChild">
<img src="#item.Blog.Image.img_path" alt="Not Found" />
<br />
#foreach (var comment in item.Blog.comment)
{
var db = new ACapture.Models.ACaptureDB();
var Name = from p in db.Profile.AsEnumerable()
where (p.AccountID == comment.AccountID)
select p;
<section>
<div>
<a href="#Url.Action("Index", "Home")">#foreach (var y in Name)
{ #(y.FirstName + " " + y.LastName + ":");
}</a>
</div>
<div>
#comment.Commentation
</div>
</section>
}
</div>
}
</div>
Thanks in advance
#{
int counter=0;
}
#foreach (var item in Model)
{
counter++;
<div class="#(counter<=3 ? "classRed":"classBlue")">
<img src="#item.Blog.Image.img_path" alt="Not Found" />
//other markup also here
</div>
if (counter == 6)
{
counter = 0;
}
}
Where classRed and classBlue are the CSS classes
How we handle this issue:
1) you need to create helper method that will return css class by some code.
string GetDivClass(int code)
{
var classes = new [] {"first", "second", "third"};
return classes[code];
}
2) create counter/index and increment it in the loop each time.
3) invoke helper method like GetDivClass(index % 3) at the div element.
PS
It is only POC, so don't use it in a real application (you need to add a validation logic and move 'classes' initialization to another place).
You can write any code you like into a Razor view, so to do what you're thinking of, you could do something like this (I left out most of the inner stuff):
#{
var className = "ForumChild";
}
<div>
#for (int i = 0; i < Model.Count; i++)
{
var item = Model[i];
if (i % 3 == 0)
className = GetNewClassName(); // Or whatever
<div class="#className">
</div>
}
</div>
You can add a counter variable to will start with 1 and increment in loop. Check with if statement is true by % and change the class name
#{ int counter = 1;}
#foreach (var item in Model)
{
if( (counter % 3) ==0 )
{
<div class="ChangedName">
}
else
{
<div class="ForumChild">
}
i++;