Reputation: 11522
I'm new to the world of 'Entity Framework' and 'Code First' so bear with me. I have 2 entities Articles and Tags. The TagName column in Tags has to be unique as it's the key. I'm having a primary key violation issue when an existing tag is used in subsequent articles. My entities look as follows
public class Article
{
public Article()
{
}
public int Id { get; set; }
[StringLength(100)]
[Required]
public string Title { get; set; }
[Required]
public string Body { get; set; }
public virtual List<Tag> Tags { get; set; }
}
and
public class Tag
{
public Tag()
{
}
public Tag(string tagName)
{
TagName = tagName;
}
[Key]
[StringLength(25)]
public string TagName { get; set; }
public virtual List<Article> Articles { get; set; }
public override string ToString()
{
return this.TagName;
}
}
EF creates 3 tables for Articles, Tags and TagArticles relationships
Here's my code to save the article
var editedTags = Request["Tags"];
if (!string.IsNullOrEmpty(editedTags))
{
var tags = Regex.Split(editedTags, "\r\n");
if (tags != null && tags.Length > 0)
{
foreach (var tag in tags)
{
article.Tags.Add(new Tag(tag));
}
}
}
//db is my context
db.Articles.Add(article);
db.SaveChanges(); //Crashes here if the tag already exists
Aside from creating the tags manually, is there a way to tell EF to check if a tag exists first before creating it so to avoid duplication?
Upvotes: 1
Views: 1176
Reputation: 11522
Found a solution. For the Tag
class, I added an int column Id and made it the primary key. I then updated the database to reflect the changes. Here it is:
public class Tag
{
public Tag()
{
}
public Tag(string tagName)
{
TagName = tagName;
}
[Key]
public int Id { get; set; }
[Required]
[StringLength(25)]
public string TagName { get; set; }
public virtual List<Article> Articles { get; set; }
public override string ToString()
{
return this.TagName;
}
}
I added a function that adds new tags to the article
private Article ParseTags(Article article)
{
var strTags = Request["Tags"];
if (!string.IsNullOrEmpty(strTags))
{
var arrTags = Regex.Split(strTags, "\r\n");
if (arrTags != null && arrTags.Length > 0)
{
foreach (var tagName in arrTags)
{
var tag = db.Tags.FirstOrDefault(t => t.TagName.ToLower() == tagName.ToLower());
if (tag == null)
article.Tags.Add(new Tag(tagName));
else
article.Tags.Add(tag);
}
}
}
return article;
}
Finally the Create
action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="Title,Body")] Article article)
{
if (ModelState.IsValid)
{
db.Articles.Add(ParseTags(article));
db.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
Now only new tags are created and existing ones are not duplicated and the relationship are properly created in the TagsArticles join table.
Upvotes: 1
Reputation: 424
Replce following line of your code
foreach (var tag in tags)
{
article.Tags.Add(new Tag(tag));
}
With
foreach (var tag in tags)
{
Tag objTag = db.Tags.SingleOrDefault(c => c.TagName == tag);
if (!(objTag != null && objTag.TagName == tag))
objTag = new Tag(tag);
article.Tags.Add(objTag);
}
Upvotes: 0