I'm creating import from XML function for categories.
First of all, using XDocument, I create list of categories to be added. I turned off isIdentity option for ID in Categories table, because I'm planning to use ID from XML.
XML example:
<cat>
<id>17</id>
<name>Category name</name>
<parent_id>0</parent_id>
</cat>
Then, I wrote method, which tries to get category by ID and update, or insert new:
var category = _categoryService.GetCategoryById(Id);
if (category != null)
{
category.Name = model.Name;
category.ParentCategoryId = model.ParentCategoryId;
category.UpdatedOnUtc = DateTime.UtcNow;
category.Published = true;
category.Deleted = false;
_categoryService.UpdateCategory(category);
}
else
{
category = new Core.Domain.Catalog.Category();
category.Id = model.Id;
category.ParentCategoryId = model.ParentCategoryId;
category.Name = model.Name;
category.UpdatedOnUtc = DateTime.UtcNow;
category.CreatedOnUtc = DateTime.UtcNow;
category.Published = true;
category.Deleted = false;
_categoryService.InsertCategory(category);
}
And then comes the most weird - application throws exception: Cannot insert the value NULL into column 'Id', table 'nopCommerce.dbo.Category'; column does not allow nulls. INSERT fails.
The statement has been terminated.
BUT even in debugger, category ID is not null.. Asking for help!
Thanks in advance!
Update: InsertCategory is a standard nopCommerce method:
/// <summary>
/// Inserts category
/// </summary>
/// <param name="category">Category</param>
public virtual void InsertCategory(Category category)
{
if (category == null)
throw new ArgumentNullException("category");
_categoryRepository.Insert(category);
//cache
_cacheManager.RemoveByPattern(CATEGORIES_PATTERN_KEY);
_cacheManager.RemoveByPattern(PRODUCTCATEGORIES_PATTERN_KEY);
//event notification
_eventPublisher.EntityInserted(category);
}
Your code seems fine presented here seems OK. I'd say you have a problem on your InsertCategory method which is most likely not making use of the id. This is just a guess... If this is not the answer, perhaps you can let us know what you have under it.
I just found out, that I need to change mapping class as well as database, removing autonumber option from ID. That was another pain, but solution is:
instead of this.HasKey(c=>c.Id) use:
this.Property(c=>c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) ;
Related
I have created a trigger that will auto-create a contact when a specific Account record type is created or updated. The problem is that I am not sure how to populate the Contact 'Account Name' lookup field. This field is a lookup to the Account object. My code is below. Any help on how to integrate this missing component would be greatly appreciated.
trigger autoCreateContact on Account (after update, after insert)
{
List newContact = new List();
for (Account oAccount : trigger.new)
{
if (oAccount.RecordTypeid == '012F0000001MCfgIAG')
{
List<Contact> cCheck = [SELECT ID From Contact WHERE LastName=:oAccount.Name];
if(cCheck.isEmpty()==True)
{
System.debug(oAccount);
Contact oContact = new Contact();
oContact.LastName = oAccount.Name;
oContact.phone = oAccount.Phone;
oContact.email = oAccount.Email__c;
oContact.Owner = oAccount.Owner;
newContact.add(oContact);
}
}
if(newContact.isEmpty() == false)
{
Database.insert(newContact);
}
}
}
nice trigger I'm pretty sure you just need to add one line which is a reference to the account.id.
So if I were you I would add the link:
oContact.AccountID = oAccount.id;
NOTE: its not a good practice to have a SOQL inside the for loop.
I am inserting a document and i want references id of document to a part of this
document...but the code is autoincrement, and i am using poco. how i can get
back the code of insert file?
ArquivoDTO file = new ArquivoDTO();
file.NomeArquivo = fileName;
file.TipoArquivo = fileType;
file.TamanhoArquivo = fileSize;
var context = new PROGISContext();
ArquivoRepository arquivoRepository = new ArquivoRepository(context);
arquivoRepository.IncluirArquivo(file); //insert file
ParteArquivoDTO part = new ParteArquivoDTO(); //create a part
part.CodArquivo = file.CodArquivo; // here id of inserted file
Something like this
[Key, DatabaseGenerated( DatabaseGeneratedOption.Identity )]
public Guid Identifier { get; protected set; }
However you won't get the I'd untill you call SaveChanges()
It's kind of hard to say what's the problem with this code sample alone, but are you calling SubmitChanges() on your DataContext in arquivoRepository.IncluirArquivo(file)?
If you are, and the CodArquivo property of your ArquivoDTO class it correctly configured to be an auto increment ID, then the property should get updated automatically after SubmitChanges().
<dx:ASPxGridView ID="ASPxGridView1" runat="server" AutoGenerateColumns="False"
KeyFieldName="CategoryID">
<SettingsEditing Mode="Inline" />
<Columns>
<dx:GridViewCommandColumn VisibleIndex="0">
<EditButton Visible="True"></EditButton>
<NewButton Visible="True"></NewButton>
<DeleteButton Visible="True"></DeleteButton>
</dx:GridViewCommandColumn>
<dx:GridViewDataTextColumn Caption="CategoryID" FieldName="CategoryID"
VisibleIndex="1">
</dx:GridViewDataTextColumn>
<dx:GridViewDataTextColumn Caption="CategoryName" FieldName="CategoryName"
VisibleIndex="2">
</dx:GridViewDataTextColumn>
<dx:GridViewDataTextColumn Caption="Description" FieldName="Description"
VisibleIndex="3">
</dx:GridViewDataTextColumn>
</Columns>
</dx:ASPxGridView>
C# syntax:
NorthwindDataContext db = new NorthwindDataContext();
var lresult = (db.Categories
.Select(p => new { p.CategoryID, p.CategoryName, p.Description}));
ASPxGridView1.DataSource = lresult;
ASPxGridView1.DataBind();
If you run the code, you get a gridview which is filled by NorthWind Categories table. If you click on command button of grid whose are on left side, you get insert/update field, but you have not access to give input. They are gone to read only mode.
If I replace the above C# syntax with below
NorthwindDataContext db = new NorthwindDataContext();
var lresult = (db.Categories);
ASPxGridView1.DataSource = lresult;
ASPxGridView1.DataBind();
then it works fine. Now you can work with command button with out facing any problem.
I want to know what the problem is, why the first syntax does not work. Maybe you say
Anonymous types are class types that consist of one or more public read-only properties. But when you need to join more than one table and need to select several fields not all than what you do. Hope you not say linq is fail to do that or Don't think it is possible. Hope there must be any technique or else something to bind control with Anonymous type. Plz show some syntax .
The problem is that the result set is collection of Anonymous type as you supposed and the grid doesn't know how to treat it. What you have to do is to use RowInserting and RowUpdating events of the grid.
Here is an example of how I use DevExpress grid with NHibernate:
protected void gridAgentGroups_RowInserting(object sender, DevExpress.Web.Data.ASPxDataInsertingEventArgs e)
{
ASPxGridView currentGrid = sender as ASPxGridView;
var currentAgentGroup = new AgentGroup();
if (e.NewValues.Contains("Name"))
{
var newValue = (string)e.NewValues["Name"];
currentAgentGroup.Name = newValue;
}
if (e.NewValues.Contains("PhysicalAddress"))
{
var newValue = (string)e.NewValues["PhysicalAddress"];
currentAgentGroup.PhysicalAddress = newValue;
}
AgentGroupsDataAccess.SaveAgentGroup(currentAgentGroup);
e.Cancel = true;
currentGrid.CancelEdit();
currentGrid.DataBind();
}
protected void gridAgentGroups_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
ASPxGridView currentGrid = sender as ASPxGridView;
int currentAgentGroupId = (int)((AgentGroup)currentGrid.GetRow(currentGrid.EditingRowVisibleIndex)).Id;
var currentAgentGroup = AgentGroups.Where(ag => ag.Id == currentAgentGroupId).FirstOrDefault();
if (e.NewValues.Contains("Name"))
{
var newValue = (string)e.NewValues["Name"];
currentAgentGroup.Name = newValue;
}
if (e.NewValues.Contains("PhysicalAddress"))
{
var newValue = (string)e.NewValues["PhysicalAddress"];
currentAgentGroup.PhysicalAddress = newValue;
}
AgentGroupsDataAccess.SaveAgentGroup(currentAgentGroup);
e.Cancel = true;
currentGrid.CancelEdit();
currentGrid.DataBind();
}
I hope this will help.
Just a wild guess - you're binding your data to the grid using field names - yet, your anonymous type doesn't really have any field names.
Does it make any difference if you try this code:
NorthwindDataContext db = new NorthwindDataContext();
var lresult = (db.Categories
.Select(p => new { CategoryID = p.CategoryID,
CategoryName = p.CategoryName,
Description = p.Description}));
ASPxGridView1.DataSource = lresult;
ASPxGridView1.DataBind();
Again - I don't have the means to test this right now, it's just a gut feeling..... try it - does that help at all??
You actually can bind with anonymous type as you see the already filled rows. But: the grid itself cannot know how you build the query and what to add additionally to the visible columns (if there are valid default values).
As you use Developer Express' grid you have the option to provide your own update / edit form and handle everything needed on your own.
I have a property in umbraco that uses a drop down data type with a set of prevalues that you can select from.
How do I retrieve a list of all the possible prevalues that are in this drop down list?
There's a helper method in umbraco.library that does that.
From xslt:
<xsl:variable name="prevalues" select="umbraco.library:GetPreValues(1234)" />
From code:
using umbraco;
XPathNodeIterator prevalues = library.GetPrevalues(1234);
Replace 1234 with the id of your datatype (You can see it in the bottom of your browser when hovering your mouse over the datatype in the developers section)
Regards
Jesper Hauge
Here is the code that I use in one of my Umbraco datatypes to get a DropDownList containing all possible prevalues:
var prevalues = PreValues.GetPreValues(dataTypeDefinitionId);
DropDownList ddl = new DropDownList();
if (prevalues.Count > 0)
{
for (int i = 0; i < prevalues.Count; i++)
{
var prevalue = (PreValue)prevalues[i];
if (!String.IsNullOrEmpty(prevalue.Value))
{
ddl.Items.Add(new ListItem(prevalue.Value, prevalue.DataTypeId.ToString()));
}
}
}
Replace dataTypeDefinitionId with the id of your datatype.
I know this is an old question, but I created this method based on the information provided in this answer and I think it is worth documenting:
public static class UmbracoExtensions
{
public static IEnumerable<string> GetDropDownDataTypeValues(int dataTypeId)
{
var dataTypeValues = umbraco.library.GetPreValues(dataTypeId);
var dataTypeValuesEnumerator = dataTypeValues.GetEnumerator();
while (dataTypeValues.MoveNext())
{
dynamic dataTypeItem = dataTypeValues.Current;
yield return dataTypeItem.Value;
}
}
}
how come this work
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == 1
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
but this does not
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == postId
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
The issue is most likely in the implementation of the query provider.
pcm.PostId == 1
and
pcm.PostId == postId
actually have a big difference. In the expression tree the first is generated as a ConstantExpression which doesnt need to be evaulated.
With the second, the compiler actually generates an inner class here (this is the _DisplayClassX that you see). This class will have a property (will most likely be the same name as your parameter) and the expression tree will create a MemberAccessExpression which points to the auto-generated DisplayClassX. When you query provider comes accross this you need to Compile() the Lambda expression and evaluate the delegate to get the value to use in your query.
Hope this helps.
cosullivan
The problem is not the linq itself,
you need to be sure that the context or provider object is able to fetch the data.
try testing the
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
objects and see if they are populated or if they behaving as required.
you may want to search the generated code for c__DisplayClass1 and see what you can see there. some times the generated code dose some weird things.
when you step into you code check the locals and the variable values. this may also give you some clues.
Edit : Have you tried to return a List<> collection ? or an Enumerable type?
Edit : What is the real type of the item and query may not be iterable