Error while updating VersionData field of ContentVersion object - salesforce

When i am updating versiondata field of contentversion object it is throwing this error :
You can't set the VersionData when IsMajorVersion is true.: []
But IsMajorVersion field is also not writeable.
Has anyone got any solution for how to update versiondata field of contentversion?? Or any workaround for this?
Previsouly i was able to update this field but unfortunately it is not working now.
Any help will be greatly appreciated.
Thanks

I had the same problem.
My solution was to create the file from salesforce apex in the first place, with the majorversion set false, then update works.
here's an example that write a TEXT file
remember if its not text (for example if its PDF) the string you give it must be b64 encoded
public string write_file(string filename, string file_txt){
ContentVersion f = new ContentVersion();
list <ContentVersion> flist =
[select id, title, ContentSize, PathOnClient, VersionData
from ContentVersion
where title = : filename
and FileExtension = 'txt'
and isMajorVersion = false
limit 1
];
if ( flist.size() > 0 ){
f = flist[0];
f.VersionData = blob.valueOf(file_txt);
update f;
}else{
f.title = filename;
f.PathOnClient = filename + '.txt';
f.VersionData = blob.valueOf(file_txt);
f.IsMajorVersion = false;
insert f;
}
return('OK');
}

Related

How can i use an Excel File in a Static Resource and Access its Fields in Salesforce Apex

I want to get values in my code from a static resource file.
I am using an excel file in a static resource, I want to know how I can map fields in an excel file to salesforce fields in my code. for example Account.Name etc
Lead l = new Lead();
l.Company = $Resource.EMailServicesLead.EmailServiceStaticResourceData.csv;
\ Not Working
EMailServicesLead - Name of the static resource.
EmailServiceStaticResourceData - csv file with fields {FirstName, LastName, Email, Company, Status, LeadSource}
/**
* #File Name : myHandler.cls
* #Description :
* #Author : ChangeMeIn#UserSettingsUnder.SFDoc
* #Group :
* #Last Modified By : ChangeMeIn#UserSettingsUnder.SFDoc
* #Last Modified On : 7/10/2019, 3:54:01 PM
* #Modification Log :
* Ver Date Author Modification
* 1.0 7/10/2019 ChangeMeIn#UserSettingsUnder.SFDoc Initial Version
**/
global with sharing virtual class myHandler implements Messaging.InboundEmailHandler
{
global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope)
{ Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
//Lead l= (Lead)ListofLeadsStaticRes[0];
// List<SObject> ListofLeadsStaticRes = {!URLFOR($Resource.EMailServicesLead, 'EmailServiceStaticResourceData.csv')};
Integer j=0;
String myPlainText= '';
staticResource sr = new staticResource();
List<sObject> ls = Test.loadData(Lead.sObjectType, 'myResource');
// {!URLFOR($Resource.EMailServicesLead,EMailServicesLead/EmailServiceStaticResourceData.csv)}
Lead l = new Lead();
l.FirstName=email.fromName.substring(0,email.fromName.indexOf(''));
l.LastName=email.fromName.substring(email.fromName.indexOf(''));
l.Email = envelope.fromAddress;
myPlainText = email.plainTextBody;
l.Company = $Resource.EMailServicesLead.EmailServiceStaticResourceData.csv;
l.Status = $Resource.EMailServicesLead.EmailServiceStaticResourceData.csv;
l.LeadSource = $Resource.EMailServicesLead.EmailServiceStaticResourceData.csv;
l.Description = 'Mr.' + l.FirstName + l.LastName + ' enquired about the product Fin' + ' via' + ' Ă‹mail' + 'with body '+myPlainText;
Task[] newTask = new Task[0];
try { // Add a new Task to the Lead record we just found above.
List<Lead> vLed = [SELECT Id, Name, Email FROM Lead WHERE Email = :email.fromAddress LIMIT 1];
if(vLed.size()>0)
{ newTask.add(new Task(Description = myPlainText,
Priority = 'Normal',
Status = 'Inbound Email',
Subject = email.subject,
IsReminderSet = true,
ReminderDateTime = System.now()+1,
WhoId = vLed[0].Id));
insert newTask;
System.debug('New Task Object: ' + newTask );
}
else
{
insert l;
System.debug('Lead Created'+ l.Id);
}
}
catch (QueryException e) { System.debug('Query Issue: ' + e); }
return result;
}
}
You will need to parse the CSV to extract the data from it. To make this easier you can use this simple CSV parser class written by Nicolas Galler. Have a look through the code so you get how it works but all you will use is the constructor and the readLine() method that returns the list of values from each row of your CSV as Strings. You'll have to copy and paste the code from that link into an apex class named "SSSCsvReader" to be able to use it then in your code you will...
1. get your static resource CSV as a String
StaticResource sr = [SELECT ID, body FROM StaticResource WHERE Name = 'EMailServicesLead' LIMIT 1];
String csvData = sr.body.toString();
2. Create an instance of SSSCsvReader by calling the constructor passing in the CSV string as the argument(and optionally, the second argument of a delimiter but the comma is the default)
SSSCsvReader csvR = new SSSCsvReader(csvData);
3. Use the readLine() on your SSSCsvReader object to get CSV field values in a String list. (if Your file has a header row on it don't forget to remove this first by calling readLine() once before getting your data list).
csvR.readLine() //Removing header (optional)
String[] line = csvR.readLine();
if(line == null){return null} //No line in the file or there was no header so return
4. Assign each field in the returned list from readLine() to the corresponding field in your salesforce object.
Lead l = new Lead();
l.firstName = line[0]; //If your file is laid out like you said FirstName will be index [0]
l.lastName = line[1]; //LastName will be index [1]
.... //And so on
....
....
And there you have it a Lead object with fields from your CSV static resource file. If you have more rows on you CSV and want to create many leads than just set up a while loop that gets each line from the CSV using readLine(), create a new lead from this line and add it to a list.

How to use 'contains' with manytomany field?

I have a model:
class Tasks(models.Model):
name = models.CharField(max_length = 50, null = True, blank = True)
assigned_to = models.ManyToManyField(User, null = True, blank = True)
I have to execute a query
tasks_for_myuser = Tasks.objects.filter(assigend_to__contains = myuser)
But this is throwing an error.
django.core.exceptions.FieldError: Related Field got invalid lookup: contains
Please help!
If you are trying to filter Tasks which has assigned_to field set to myuser, you can simply query like this.
tasks_for_myuser = Tasks.objects.filter(assigend_to = myuser)
You don't really require contains here, since it is a many-to-many field.

How to read data from csv file when file name changes at runtime after downloading

I am trying to automate download csv file and read data from there.
I tried with:
CSVReader reader = new CSVReader(new FileReader("D:\\File\\1453.csv"));
String [] csvCell;
//while loop will be executed till the last line In CSV.
while ((csvCell = reader.readNext()) != null) {
String FName = csvCell[0];
String LName = csvCell[1];
String Email = csvCell[2];
String Mob = csvCell[3];
String company = csvCell[4];
but the problem is here I need to give the file name while mentioning the path, here I can't write the name as it is getting changed at runtime after downloading. Please suggest
If the filename is same as the download link (even if it is partial), you can get the link from the download button or whatever element it is using getAttribute("href") and then you can use it to form the filename to read from.
String fileName = driver.findElement("<download_locator>").getAttribute("href")
CSVReader reader = new CSVReader(new FileReader("D:\\File\\" + fileName));
String [] csvCell;
//while loop will be executed till the last line In CSV.
while ((csvCell = reader.readNext()) != null) {
String FName = csvCell[0];
String LName = csvCell[1];
String Email = csvCell[2];
String Mob = csvCell[3];
String company = csvCell[4];
Have you tried this? And passing in the parameter from a method?
CSVReader reader = new CSVReader(new FileReader("D:\\File\\" + provideFileName));

I Want to Read .word format Document body and To display the content of body in VF Page as a String

I Have uploaded a .word file in Document Object.Now I want to get that content(body) of that file and I want to dislay whole content in Visual Force Page.
Document doc = [Select d.body from Document d where d.name='docname';
Blob b = doc.body;
String Str = b.toString();
//This Giving an Error Encoding UTC8.
//Then Modified to like below but it's not giving correct data.
//It's giving like #5ywnnn7*96w**.
Document doc = [Select d.body from Document d where d.name='docname';
Blob b = doc.body;
String Str = EncodingUtil.base64Encode(b);
Thanks In Advance.

Parse XML with Linq

I have the following XML document which I would like to parse into a DataSet.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response Status="OK">
<Item>
<Field Name="ID">767147519</Field>
<Field Name="Name">Music</Field>
<Field Name="Path">Family\Music</Field>
<Field Name="Type">Playlist</Field>
</Item>
</Response>
I am wanting to get the attribute values for ID, Name, and Path.
The following is what I have attempted:
Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Item") Select c
For Each result In name
Dim str1 = result.Attribute("ID").Value 'Returns Nothing and causes a validation error
Dim str2 = result.Value ' Returns all the attribute values in one long string (ie "767147519MusicFamilyPlaylist")
Next
Any help would be greatly appreciated.
Thanks,
Matt
EDIT:
Following one of the answers below, I have been attempting to implement an anonymous type in my Linq, however I keep encountering the error
Object reference not set to an
instance of an object.
My updated code is as follows:
Dim name = From c In loaded.Descendants("Item") Select c Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault
Dim Id As String = String.Empty
For Each result In name
Id = result.sID
Next
I think this error means that the attribute ("ID") cannot be located, so I have attempted several variations of this with similar results.
Is anyone able to identify where I am going wrong and point me in the right direction.
Thanks,
Matt
You can use XPath:
Dim data = From item In loaded.Descendants("Item")
Select
ID = item.XPathSelectElement("Field[#Name='ID']").Value,
Name = item.XPathSelectElement("Field[#Name='Name']").Value,
Path = item.XPathSelectElement("Field[#Name='Path']").Value,
Type = item.XPathSelectElement("Field[#Name='Type']").Value
(Be sure to import the System.Xml.XPath namespace)
Or to add it directly to a DataTable:
Dim dt As New DataTable()
dt.Columns.Add("ID")
dt.Columns.Add("Name")
dt.Columns.Add("Path")
dt.Columns.Add("Type")
For Each item In loaded.Descendants("Item")
dt.Rows.Add(
item.XPathSelectElement("Field[#Name='ID']").Value,
item.XPathSelectElement("Field[#Name='Name']").Value,
item.XPathSelectElement("Field[#Name='Path']").Value,
item.XPathSelectElement("Field[#Name='Type']").Value
)
Next
Another one solution with anonymous types:
var doc = XDocument.Load("c:\\test");
var list = doc.Root
.Elements("Item")
.Select(item =>
new
{
Id = item.Elements("Field").Where(e => e.Attribute("Name").Value == "ID").Select(e => e.Value).FirstOrDefault(),
Path = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Path").Select(e => e.Value).FirstOrDefault(),
Name = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Name").Select(e => e.Value).FirstOrDefault(),
})
.ToArray();
foreach (var item in list)
{
var id = item.Id;
var name = item.Name;
}
Ugly expression inside new operator can be shorted with next anonymous function:
Func<XElement, string, string> getAttrValue = (node, attrName) =>
{
return node.Elements("Field")
.Where(e => e.Attribute("Name").Value == attrName)
.Select(e => e.Value)
.FirstOrDefault();
};
Then new operator looks like:
new
{
Id = getAttrValue(item, "ID"),
Path = getAttrValue(item, "Path"),
Name = getAttrValue(item, "Name"),
}
Here is my attempt at solution to your problem. I just noticed that you wish to go with as much LINQ as possible so I've structured my LINQ query accordingly. Please note result type (for "IDs") will be IEnumerable() i.e. you will need to run a for each loop on it to get individual ids even with a single item:
Dim loaded As XDocument = XDocument.Load(uriString)
Dim IDs = From items In loaded.Descendants("Item") _
Let fields = items.Descendants("Field") _
From field In fields _
Where field.Attribute("Name").Value = "ID" _
Select field.Value
On a side note: For future reference, if you run into C# anonymous type "var" in examples, the equivalent in vb is plain dim like in my query above (without the 'as type' part).
Hope this helps.
Maverik
Use XPath and save everyone the headaches?
XmlDocument xml = new XmlDocument();
xml.Load(xmlSource);
string id = xml.SelectSingleNode("/Response/Item/Field[#Name='ID']").InnerText;
string name = xml.SelectSingleNode("/Response/Item/Field[#Name='Name']").InnerText;
string path = xml.SelectSingleNode("/Response/Item/Field[#Name='Path']").InnerText;
I am wanting to get the attribute values for ID, Name, and Path.
If you don't mind using something else than XDocument i'd just use a XmlDocument:
XmlDocument doc = new XmlDocument();
doc.Load(new XmlTextReader("XData.xml"));
XmlNodeList items = doc.GetElementsByTagName("Item");
foreach (XmlElement item in items.Cast<XmlElement>())
{
XmlElement[] fields = item.GetElementsByTagName("Field").Cast<XmlElement>().ToArray();
string id = (from s in fields where s.Attributes["Name"].InnerText == "ID" select s).First().InnerText;
string name = (from s in fields where s.Attributes["Name"].InnerText == "Name" select s).First().InnerText;
string path = (from s in fields where s.Attributes["Name"].InnerText == "Path" select s).First().InnerText;
//Do stuff with data.
}
Performance-wise this might be abysmal. You could also have a loop on the Fields and then use a switch on the Name-Attribute so you don't check the same field more than once. Why would you need any linq for this anyway?
XmlDocument doc = new XmlDocument();
doc.Load(new XmlTextReader("XData.xml"));
XmlNodeList items = doc.GetElementsByTagName("Item");
foreach (XmlElement item in items.Cast<XmlElement>())
{
foreach (XmlNode field in item.GetElementsByTagName("Field"))
{
string name = field.Attributes["Name"].InnerText;
switch (name)
{
case "ID":
string id = field.InnerText;
//Do stuff with data.
break;
case "Path":
string path = field.InnerText;
//Do stuff with data.
break;
case "Name":
string name = field.InnerText;
//Do stuff with data.
break;
default:
break;
}
}
}
Your linq query returns all the Item elements in the document:
Dim name = From c In loaded.Descendants("Item") Select c
The code that follows is trying to obtain an 'ID' attribute from the 'Item' element:
Dim str1 = result.Attribute("ID").Value
However, the 'ID' attribute is on a 'Field' child element.
What you need is the following:
// find all the Item elements
var items = loaded.Descendants("Item");
foreach(var item in items)
{
// find all the Field child elements
var fields = item.Descendants("Field");
// find the field element which has an ID attribute, and obtain the element value
string id = fields.Where(field => field.Attribute("ID")!=null)
.Single()
.Value;
// etc ...
}
A Simple solution is
var result = doc.Root.Descendants(XName.Get("Item")).Select(x => x.Descendants(XName.Get("Field")));
foreach (var v in result)
{
string id = v.Single(x => x.Attribute(XName.Get("Name")).Value == "ID").Value;
string name = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Name").Value;
string path = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Path").Value;
string type = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Type").Value;
}
It can be easily converted in to vb code.
Here is a generic solution that handles all fields with different field names in several items. It saves the result in one table containing all distinct field names as column names.
Module Module1
Function createRow(ByVal table As DataTable, ByVal item As XElement) As DataRow
Dim row As DataRow = table.NewRow
Dim fields = item.Descendants("Field")
For Each field In fields
row.SetField(field.Attribute("Name").Value, field.Value)
Next
Return row
End Function
Sub Main()
Dim doc = XDocument.Load("XMLFile1.xml")
Dim items = doc.Descendants("Item")
Dim columnNames = From attr In items.Descendants("Field").Attributes("Name") Select attr.Value
Dim columns = From name In columnNames.Distinct() Select New DataColumn(name)
Dim dataSet As DataSet = New DataSet()
Dim table As DataTable = New DataTable()
dataSet.Tables.Add(table)
table.Columns.AddRange(columns.ToArray())
Dim rows = From item In items Select createRow(table, item)
For Each row In rows
table.Rows.Add(row)
Next
' TODO Handle Table
End Sub
End Module
I tried to use as much Linq as possible, but Linq is a bit inflexible when it comes to handling nested elements recursively.
Heres the sample xml file I've used:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response Status="OK">
<Item>
<Field Name="ID">767147519</Field>
<Field Name="Name">Music</Field>
<Field Name="Path">Family\Music</Field>
<Field Name="Type">Playlist</Field>
</Item>
<Item>
<Field Name="ID">123</Field>
<Field Name="Name">ABC</Field>
<Field Name="RandomFieldName">Other Value</Field>
<Field Name="Type">FooBar</Field>
</Item>
</Response>
And the result:
ID Name Path Type RandomFieldName
767147519 Music Family\Music Playlist
123 ABC FooBar Other Value
After some further research and with the assistance of parts from the answers provided, I have come up with the following, which returns the information that I am after.
Dim Query = From items In loaded.Descendants("Item") _
Let sID = ( From q In items.Descendants("Field") _
Where q.Attribute("Name").Value = "ID" ) _
Let sName = ( From r In items.Descendants("Field") _
Where r.Attribute("Name").Value = "Name" ) _
Let sPath = ( From s In items.Descendants("Field") _
Where s.Attribute("Name").Value = "Path" ) _
Where (Ctype(sPath.Value,String) Like "Family\*") _
Select pId=sID.Value, pName=sName.Value, pPath = sPath.Value
If this can be improved in any way to enable better performance, please let me know.
Thank you all for your assistance, while no one answer was able to entirely solve the problem I was able to learn a great deal about Linq through everyones assistance.
Matt
I hope you expected something like this short answer and not another implementation:
Dim items = From c In loaded.Descendants("Item") Select c (...)
Ok so far nothing should run into any trouble. The variable name 'name' was a bit confusing, so I changed it to 'items'.
The second part contains the error:
Dim items = (...) Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault
The following works because there is an Attribute called Name, although the result is 'ID' what shurely wasn't expected:
c.Element("Field").Attribute("Name").Value
Here comes the error:
c.Attribute("ID").Value.FirstOrDefault
c is the XmlNode '< Item > ... < / Item >' and it does not have any attributes, thus the result of c.Attribute("ID") is null.
I guess you wanted something like the following:
Dim loaded = XDocument.Load("XMLFile1.xml")
Dim items = From item In loaded.Descendants("Item") Select _
sID = (From field In item.Descendants("Field") _
Where field.Attribute("Name") = "ID" _
Select field.Value).FirstOrDefault() _
, _
sName = (From field In item.Descendants("Field") _
Where field.Attribute("Name") = "Name" _
Select field.Value).FirstOrDefault()
There are a few errors in your code:
You should get the Descendents that have the XName equal to Field instead of to Item
Dim name = From c In loaded.Descendants("Field") Select c
The attribute you are after is called Name, not ID
Dim str1 = result.Attribute("Name").Value
At the first iteration of your for each str1 will be "ID", the next one it will be "Name", etc.
Total code:
Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Field") Select c
For Each result In name
Dim str1 = result.Attribute("Name").Value 'Returns "ID"
Dim str2 = result.Value ' Returns "767147519"
Next
There's another way to fix this problem. Transform this XML into the format that the DataSet wants, and then load it using DataSet.ReadXml. This is something of a pain if you don't know XSLT. But it's really important to know XSLT if you work with XML.
The XSLT you'd need is pretty simple. Start with the XSLT identity transform. Then add a template that transforms the Response and Item elements into the format that the DataSet expects:
<xsl:template match="Response">
<MyDataSetName>
<xsl:apply-templates select="Item"/>
</MyDataSetName>
</xsl:template>
<xsl:template match="Item">
<MyDataTableName>
<xsl:apply-templates select="Field[#Name='ID' or #Name='Name' or #Name='Path']"/>
</MyDataTableName>
</xsl:template>
<xsl:template match="Field">
<xsl:element name="{#Name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
That will change your XML to a document that looks like this:
<MyDataSetName>
<MyDataTableName>
<ID>767147519</ID>
<Name>Music</Name>
<Path>Family\Music</Path>
</MyDataTableName>
</MyDataSetName>
...and you can just feed that to DataSet.ReadXml.
Edit:
I should point out, since it's not obvious unless you do this a lot, that one effect of this is that the amount of C# code that you need to create and populate the DataSet is minimal:
private DataSet GetDataSet(string inputFilename, string transformFilename)
{
StringBuilder sb = new StringBuilder();
using (XmlReader xr = XmlReader.Create(inputFilename))
using (XmlWriter xw = XmlWriter.Create(new StringWriter(sb)))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(transformFilename);
xslt.Transform(xr, xw);
}
using (StringReader sr = new StringReader(sb.ToString()))
{
DataSet ds = new DataSet();
ds.ReadXml(sr);
return ds;
}
}
It's also reusable. You can use this method to populate as many different DataSets from as many different possible input formats as you need; you just need to write a transform for each format.

Resources