Pass JsTreeView data from database - asp.net-mvc

I have a list of virtual folder structure. I need to bind that list to JsTreeView. The List may contain something like the below.
List of Items
Dh
Dh\Sub
Dh\Sub\Another
Dh1
Dh1\Sub1
Dh1\Sub1\Another1
Dh1\Sub1\Another2
Desired Output
Dh
|______ Sub
|_____Another
Dh1
|______ Sub1
|_____ Another1
|_____ Another2
As, I have tried logic using recursion. But, did not succeed with it. Can anybody tell me how can i achieve this. Any help to the problem will be highly appreciated.
Thanks

I am using the following class to serialize DB data to JSON and load into JS Tree View
/// <summary>
/// Model which represents data for js tree view
/// </summary>
public class JsTreeViewNode
{
private int int_id;
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "children")]
public List<JsTreeViewNode> Children { get; set; }
[JsonProperty(PropertyName = "a_attr")]
public AnchorAttribute AAttributes { get; set; }
[JsonIgnore]
public int CurrentLevel { get; set; }
[JsonIgnore]
public int SortOrder { get; set; }
public JsTreeViewNode()
{
AAttributes = new AnchorAttribute();
}
public JsTreeViewNode(int id)
: this()
{
int_id = id;
this.Id = int_id.ToString();
AAttributes.Id = this.Id;
}
public int GetNodeId()
{
return int_id;
}
public JsTreeViewNode Clone()
{
var clone = (JsTreeViewNode)this.MemberwiseClone();
clone.Children = new List<JsTreeViewNode>();
clone.AAttributes = this.AAttributes.Clone();
return clone;
}
}
public class AnchorAttribute
{
[JsonProperty(PropertyName = "draggable")]
public string Draggable = "false";
[JsonProperty(PropertyName = "id")]
public string Id;
[JsonProperty(PropertyName = "class", NullValueHandling = NullValueHandling.Ignore)]
public string CssClassname;
public virtual AnchorAttribute Clone()
{
var clone = (AnchorAttribute)this.MemberwiseClone();
return clone;
}
}
Children property contains subnodes. Populating them depends on you app logic.
and later in controller
public virtual ContentResult LoadTreeData()
{
var treeData = Repository.GetTreeData();
return Content(JsonConvert.SerializeObject(treeData), "application/json");
}
Hope this helps

Related

.Net Core - Method Create Error NullReferenceException

There are already some questions about this problem, but none of them actually solved my problem.
I'm trying to create the Create method of the Student.cs entity, but when I access the create url, this error appears, I really do not know how to solve it.
AlumniController.cs
line error: 32 var teachers = await _contextProfessor.FindAllAsync ();
Image error
Code
AlunoController.cs
public class AlunosController : Controller
{
public readonly AlunosService _contextAluno;
public readonly ProfessorService _contextProfessor;
public readonly TurmasController _contextTurma;
public AlunosController(AlunosService contextAluno)
{
_contextAluno = contextAluno;
}
public async Task<IActionResult> Index()
{
var lista = await _contextAluno.FindAllAsync();
return View(lista);
}
//GET
public async Task<IActionResult> Create()
{
var professores = await _contextProfessor.FindAllAsync();
var turmas = await _contextTurma.FindAllAsync();
var viewModel = new AlunoViewModel {
Professores = professores,
Turmas = turmas
};
return View(viewModel);
}
}
Turma.cs
public class Turma
{
public int Id { get; set; }
public int Numero { get; set; }
public string Curso { get; set; }
public ICollection<Aluno> Alunos { get; set; } = new List<Aluno>();
public Turma()
{
}
public Turma(int id, int numero, string curso)
{
Id = id;
Numero = numero;
Curso = curso;
}
}
Professor.cs
public class Professor
{
public int Id { get; set; }
public string Nome { get; set; }
public string Email { get; set; }
public string Telefone { get; set; }
public ICollection<Aluno> Alunos { get; set; } = new List<Aluno>();
public Professor()
{
}
public Professor(int id, string nome, string email, string telefone)
{
Id = id;
Nome = nome;
Email = email;
Telefone = telefone;
}
}
How can I solve this?
Code Complete HERE.
_contextProfessor is null. You will need to set it in the constructor of AlunosController.
public AlunosController(AlunosService contextAluno, ProfessorService professorService)
{
_contextAluno = contextAluno;
_contextProfessor = processorService;
}
You obviously have not assigned objects to _contextProfessor and _contextTurma fields, so you will naturally get a NullReferenceException if you try to refer to their methods and properties. So, firstly, you need to inject ProfessorService and TurmasController into controller constructor.
But for injection to be successfull, you need to specify the dependecies in your Startup class ConfigureServices method, otherwise the dependecy won't be able to be resolved an InvaidOperationException will be thrown.
Because you forgot to include that service in the call in the constructor
public AlunosController(AlunosService contextAluno, ProfessorService contextProfessor)
//^^^^
{
_contextAluno = contextAluno;
_contextPrefessor = contextProfessor;
}
DI bit you a little. just because you add the one context to the constructor doesn't mean the others are instantiated for free.

How to implement Create with child collection in Application Layer?

I have 2 entities named News and NewsAttachment in the .Core Project. These entities have a relationship through News_Id. In other words, when I create new News and add it into database, this News may have one or two attachment media that I want to insert in the related table named NewsAttachment. So I may want to retrieve News_Id and insert attachments in the related table.
I define 2 DTOs named NewsDto and CreateNewsDto in NewsAppService and I pass CreateNewsDto to insert new News, but I have no idea how to do it for NewsAttachment.
Here is my News entity:
public class News : FullAuditedEntity<long>
{
public const int MaxTitleLength = 150;
public const int MaxContentLength = 1200;
public const int MaxMetaTagLength = 60;
[Required]
[MaxLength(MaxTitleLength)]
public string Title { get; set; }
[Required]
public string Code { get; set; }
[Required]
[MaxLength(MaxContentLength)]
public string Content { get; set; }
public DateTime PublishDate { get; set; }
[MaxLength(MaxMetaTagLength)]
public string Tags { get; set; }
public virtual NewsType Type { get; set; }
public virtual ICollection<NewsAttachment> Attachments { get; set; }
}
and NewsAttachment entity:
public class NewsAttachment: FullAuditedEntity<long>
{
public const int MaxTitleLength = 50;
[Required]
[MaxLength(MaxTitleLength)]
public string FileName { get; set; }
[Required]
public byte[] File { get; set; }
public string FileExtension { get; set; }
public int FileSize { get; set; }
[Required]
public DateTime RegisterDate { get; set; }
public virtual News News { get; set; }
}
and the DTOs:
public class NewsDto : EntityDto<long>
{
public const int MaxTitleLength = 50;
public const int MaxContentLength = 800;
public const int MaxMetaTagLength = 60;
[Required]
[MaxLength(MaxTitleLength)]
public string Title { get; set; }
[Required]
public string Code { get; set; }
[Required]
[MaxLength(MaxContentLength)]
public string Content { get; set; }
public DateTime PublishDate { get; set; }
[MaxLength(MaxMetaTagLength)]
public string Tags { get; set; }
public virtual NewsType Type { get; set; }
}
and:
public class CreateNewsDto
{
public const int MaxTitleLength = 50;
public const int MaxContentLength = 800;
public const int MaxMetaTagLength = 60;
[Required]
[MaxLength(MaxTitleLength)]
public string Title { get; set; }
[Required]
public string Code { get; set; }
[Required]
[MaxLength(MaxContentLength)]
public string Content { get; set; }
public DateTime PublishDate { get; set; }
[MaxLength(MaxMetaTagLength)]
public string Tags { get; set; }
public virtual NewsType Type { get; set; }
public virtual ICollection<NewsAttachment> Attachments { get; set; }
}
Here is my presumptive method in NewsAppService to insert new News and add related media to NewsAttachment table:
public virtual NewsDto InsertWithMedia(CreateNewsDto input, NewsAttachmentDto attach)
{
var news = ObjectMapper.Map<NewsManagement.News>(input);
var newsAttachment = ObjectMapper.Map<NewsAttachment>(attach);
newsAttachment.News.Id = news.Id;
return MapToEntityDto(news);
}
Two choices:
Add to ICollection and let EF handle the entities:
public virtual NewsDto InsertWithMedia(CreateNewsDto input, NewsAttachmentDto attach)
{
var news = ObjectMapper.Map<NewsManagement.News>(input);
news.Attachments = new List<NewsAttachment>(); // 1
var newsAttachment = ObjectMapper.Map<NewsAttachment>(attach);
news.Attachments.Add(newsAttachment); // 2
_newsRepository.Insert(news); // 3
CurrentUnitOfWork.SaveChanges(); // 4
return MapToEntityDto(news);
}
Add by Id instead of collection, with a foreign key:
public class NewsAttachment: FullAuditedEntity<long>
{
// ...
public virtual long NewsId { get; set; }
public virtual News News { get; set; }
}
public virtual NewsDto InsertWithMedia(CreateNewsDto input, NewsAttachmentDto attach)
{
var news = ObjectMapper.Map<NewsManagement.News>(input);
var newsId = _newsRepository.InsertAndGetId(news); // 1
var newsAttachment = ObjectMapper.Map<NewsAttachment>(attach);
newsAttachment.NewsId = newsId; // 2
_newsAttachmentRepository.Insert(newsAttachment); // 3
CurrentUnitOfWork.SaveChanges(); // 4
return MapToEntityDto(news);
}
The second is good for updating — when newsId is already known — but may require additional steps if NewsDto also has Attachments (which should be ICollection<AttachmentDto> type).
thank you #aaron. after all, I have a little problem. in .WebMpa project how can I retrieve News with related picture.I define NewsViewModel in model folder and Map this ViewModel to NewsDto with Auto Mapper library.and in NewsController call NewsAppService and GetAll method for get news from database.I have 2 Scenario for this situation:
1- I think that change this method in .Application Project and add some linq query to get News with related Pictures from NewsAttachment
2- all operation about News and NewsAttachment and join with two entity stay in .WebMpa project and NewsController.
I confused really.would you help me with show example?

Object reference not set to an instance of an object.

i have 3 model:
1st one:
public class CreateFieldModel
{
public FieldModel fm { get; set; }
public CategoryModel cm { get; set; }
}
2nd one:
public class FieldModel
{
public string field_Name { get; set; }
public InputTypeModel itm { get; set; }
public string input1 { get; set; }
public string input2 { get; set; }
public string input3 { get; set; }
public string input4 { get; set; }
public List<InputTypeModel> inputs { get; set; }
}
3rd One:
public class InputTypeModel
{
public string inputTypeName { get; set; }
public string inputTypeDesc { get; set; }
}
2 methods:
1st One:
public List<InputTypeModel> getInputTypes()
{
var inptypes = edu.InputTypes;
List<InputTypeModel> listInputTypes = new List<InputTypeModel>();
foreach (var inpType in inptypes)
{
listInputTypes.Add(new InputTypeModel { inputTypeName = inpType.Input_Type_Name, inputTypeDesc = inpType.Input_Type_Description });
}
return listInputTypes;
}
when this method executes listInputTypes has three different values.. i check it by debugging.. so no roblem here. This methos is under the class FormManagement.. I am calling this method from the following action method:
[HttpGet]
public ActionResult createNewField(CreateFieldModel cfm, string fcode)
{
FormManagement ffm = new FormManagement();
cfm.fm.inputs = ffm.getInputTypes();
return View(cfm);
}
when cfm.fm.inputs = ffm.getInputTypes(); executes it is showing "Object reference not set to an instance of an object." message... I am quite beginner to mvc.. please help
Without knowing what you really want to achieve with cfm-parameter in your action, the only thing I can suggest is to check for null references and create new instances before you assign them:
[HttpGet]
public ActionResult createNewField(CreateFieldModel cfm, string fcode)
{
FormManagement ffm = new FormManagement();
if (cfm == null)
{
cfm = new CreateFieldModel();
}
if (cfm.fm == null)
{
cfm.fm = new FieldModel();
}
cfm.fm.inputs = ffm.getInputTypes();
return View(cfm);
}
Of course, this supposes that your not relying on incoming data through your route parameters. If you are, you need to check why the values are not getting passed in, but I'm guessing you don't need it as a parameter in the first place.

How to design a ViewModel for a todo list application?

I am creating a simple todo application which has two entities, tasks and categories.
To create a task, choosing a category is a must. For this, I figured I would need a ViewModel.
Here is the Task entity
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
Here is the Category entity
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
How can I design a TaskCategoryViewModel so that I can bind the category in the CreateTask view?
Edit: I am using classic ADO.NET instead of Entity Framework or LINQ to SQL.
Kishor,
the best bet is have model that hods definition for your task and for category (all in one)
here is how everything hangs together.
where
IEnumerable<SelectListItem> Categories
is used for creating drop down list which is ready to use
<%= Html.DropDownListFor(model=>model.NewTask.categoryId, Model.Categories) %>
this will create you nice dropdown list
private IEnumerable<Category> GetCategories
{
get
{
List<Category> categories = new List<Category>
{
new Category() {categoryId = 1, categoryName = "test1"},
new Category() {categoryId = 2, categoryName = "category2"}
};
return categories;
}
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CreateTask()
{
TaskModel taskModel = new TaskModel();
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
private void LoadCategoriesForModel(TaskModel taskModel)
{
taskModel.Categories =
GetCategories.Select(
x =>
new SelectListItem()
{Text = x.categoryName, Value = x.categoryId.ToString(CultureInfo.InvariantCulture)});
}
public ActionResult CreateTask(TaskModel taskModel)
{
if (ModelState.IsValid)
{
// do your logic for saving
return RedirectToAction("Index");
}
else
{
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
}
/// <summary>
/// your model for creation
/// </summary>
public class TaskModel
{
public Task NewTask { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
/// <summary>
/// Task
/// </summary>
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
/// <summary>
/// Category
/// </summary>
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
In the TaskViewModel (I would prefer naming it CreateTaskViewModel) create property for categories select list
public IEnumerable<SelectListItem> CategoriesSelectList;
In controller, bind that property before returning view (note that this also should be done in post handler, when ModelState is invalid)
public ViewResult Create()
{
CreateTaskViewModel model = new CreateTaskViewModel();
model.CategoriesSelectList = _repository.AllCategories().Select(x=> new SelectListItem(){ Text = x.CategoryName, Value = x.CategoryId.ToString();}
}
And finally, in the view
Html.DropDownListFor(model => model.CategoryId, Model.CategoriesSelectList)
Edit:
In your code, _repository.AllCategories() should be replaced by your data access code, that returns object having type IEnumerable<Category>. It actually does not matter which data access technology you use. And do not forget to add the using System.Linq; statement to your controller file, if it's missing.

Can automapper map a foreign key to an object using a repository?

I'm trying out Entity Framework Code first CTP4. Suppose I have:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Mother { get; set; }
}
public class TestContext : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
}
Mapper.CreateMap<Child, ChildEdit>();
Mapping to the Edit model is not a problem. On my screen I select the mother through some control (dropdownlist, autocompleter, etc) and the Id of the mother gets posted in back:
[HttpPost]
public ActionResult Edit(ChildEdit posted)
{
var repo = new TestContext();
var mapped = Mapper.Map<ChildEdit, Child>(posted); // <------- ???????
}
How should I solve the last mapping? I don't want to put Mother_Id in the Child object. For now I use this solution, but I hope it can be solved in Automapper.
Mapper.CreateMap<ChildEdit, Child>()
.ForMember(i => i.Mother, opt => opt.Ignore());
var mapped = Mapper.Map<ChildEdit, Child>(posted);
mapped.Mother = repo.Parents.Find(posted.MotherId);
EDIT
This works, but now I have to do that for each foreign key (BTW: context would be injected in final solution):
Mapper.CreateMap<ChildEdit, Child>();
.ForMember(i => i.Mother,
opt => opt.MapFrom(o =>
new TestContext().Parents.Find(o.MotherId)
)
);
What I'd really like would be:
Mapper.CreateMap<int, Parent>()
.ForMember(i => i,
opt => opt.MapFrom(o => new TestContext().Parents.Find(o))
);
Mapper.CreateMap<ChildEdit, Child>();
Is that possible with Automapper?
First, I'll assume that you have a repository interface like IRepository<T>
Afterwards create the following class:
public class EntityConverter<T> : ITypeConverter<int, T>
{
private readonly IRepository<T> _repository;
public EntityConverter(IRepository<T> repository)
{
_repository = repository;
}
public T Convert(ResolutionContext context)
{
return _repository.Find(System.Convert.ToInt32(context.SourceValue));
}
}
Basically this class will be used to do all the conversion between an int and a domain entity. It uses the "Id" of the entity to load it from the Repository. The IRepository will be injected into the converter using an IoC container, but more and that later.
Let's configure the AutoMapper mapping using:
Mapper.CreateMap<int, Mother>().ConvertUsing<EntityConverter<Mother>>();
I suggest creating this "generic" mapping instead so that if you have other references to "Mother" on other classes they're mapped automatically without extra-effort.
Regarding the Dependency Injection for the IRepository, if you're using Castle Windsor, the AutoMapper configuration should also have:
IWindsorContainer container = CreateContainer();
Mapper.Initialize(map => map.ConstructServicesUsing(container.Resolve));
I've used this approach and it works quite well.
Here's how I did it: (using ValueInjecter)
I made the requirements a little bigger just to show how it works
[TestFixture]
public class JohnLandheer
{
[Test]
public void Test()
{
var child = new Child
{
Id = 1,
Name = "John",
Mother = new Parent { Id = 3 },
Father = new Parent { Id = 9 },
Brother = new Child { Id = 5 },
Sister = new Child { Id = 7 }
};
var childEdit = new ChildEdit();
childEdit.InjectFrom(child)
.InjectFrom<EntityToInt>(child);
Assert.AreEqual(1, childEdit.Id);
Assert.AreEqual("John", childEdit.Name);
Assert.AreEqual(3, childEdit.MotherId);
Assert.AreEqual(9, childEdit.FatherId);
Assert.AreEqual(5, childEdit.BrotherId);
Assert.AreEqual(7, childEdit.SisterId);
Assert.AreEqual(0, childEdit.Sister2Id);
var c = new Child();
c.InjectFrom(childEdit)
.InjectFrom<IntToEntity>(childEdit);
Assert.AreEqual(1, c.Id);
Assert.AreEqual("John", c.Name);
Assert.AreEqual(3, c.Mother.Id);
Assert.AreEqual(9, c.Father.Id);
Assert.AreEqual(5, c.Brother.Id);
Assert.AreEqual(7, c.Sister.Id);
Assert.AreEqual(null, c.Sister2);
}
public class Entity
{
public int Id { get; set; }
}
public class Parent : Entity
{
public string Name { get; set; }
}
public class Child : Entity
{
public string Name { get; set; }
public Parent Mother { get; set; }
public Parent Father { get; set; }
public Child Brother { get; set; }
public Child Sister { get; set; }
public Child Sister2 { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
public int FatherId { get; set; }
public int BrotherId { get; set; }
public int SisterId { get; set; }
public int Sister2Id { get; set; }
}
public class EntityToInt : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType.IsSubclassOf(typeof(Entity)) && targetType == typeof(int);
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName + "Id";
}
protected override bool AllowSetValue(object value)
{
return value != null;
}
protected override object SetValue(object sourcePropertyValue)
{
return (sourcePropertyValue as Entity).Id;
}
}
public class IntToEntity : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType == typeof(int) && targetType.IsSubclassOf(typeof(Entity));
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName.RemoveSuffix("Id");
}
protected override bool AllowSetValue(object value)
{
return (int)value > 0;
}
protected override object SetValue(object sourcePropertyValue)
{
// you could as well do repoType = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType))
var repoType = typeof (Repo<>).MakeGenericType(TargetPropType);
var repo = Activator.CreateInstance(repoType);
return repoType.GetMethod("Get").Invoke(repo, new[] {sourcePropertyValue});
}
}
class Repo<T> : IRepo<T> where T : Entity, new()
{
public T Get(int id)
{
return new T{Id = id};
}
}
private interface IRepo<T>
{
T Get(int id);
}
}
It's possible to define the foreign key in EF this way as well:
[ForeignKey("MotherId")]
public virtual Parent Mother { get; set; }
public int MotherId { get; set; }
In this case, It's not necessary to do an extra query to find the Mother. Just Assign the ViewModel's MotherId to the Model's MotherId.

Resources